怎么免费制作一个企业网站百度seo报价方法
目录
创建多线程的三种创建方式
常用的成员方法
守护线程
多线程的声明周期
编辑 同步代码块编辑
同步方法
死锁
等待唤醒机制(线程协调)
线程池
创建多线程的三种创建方式
继承 Thread
类
通过继承 Thread
类并重写 run()
方法创建线程。
class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread running: " + getName());}
}
public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
实现 Runnable
接口
实现 Runnable
接口并将实例传递给 Thread
对象。推荐此方式,因为可以避免 Java 单继承的限制。
class MyRunnable implements Runnable {@Overridepublic void run() {// 注意这里不能直接getName,因为getName是Thread里面的方法,我们必须先获取当前的线程在调用此方法System.out.println("Runnable running: " + Thread.currentThread().getName());}
}
public class Main {public static void main(String[] args) {// 创建MyRun的对象 表示多线程要执行的任务MyRun mr = new MyRun();// 创建线程对象Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);t1.start();t2.start();}
}
通过 Callable
和 FutureTask
Callable
可以返回结果或抛出异常,结合 FutureTask
执行。
import java.util.concurrent.Callable;
// 第三种开启线程的方法;特点:可以得到多线程运行的结果
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {// 开启线程 求1~100之间的和int sum = 0;for (int i = 1; i <100 ; i++) {sum+=i;}return sum;}
}
public class ThreadDemo {public static void main(String[] args) throws ExecutionException, InterruptedException{// 第三种方式:MyCallable mc = new MyCallable();FutureTask<Integer> ft = new FutureTask<>(mc);Thread t1 = new Thread(ft);// 给线程设置名字t1.setName("线程1");// 开启线程t1.start();Integer result = ft.get();System.out.println(result);}
}
常用的成员方法
start()
: 启动线程并调用run()
方法。run()
: 线程执行的具体逻辑。join()
: 等待线程执行结束。sleep(long millis)
: 暂停当前线程执行一段时间。yield()
: 暂时释放 CPU 资源,让其他线程有机会执行。getName()
/setName()
: 获取或设置线程名称。isAlive()
: 检查线程是否仍然存活。setPriority(int priority)
: 设置线程优先级。
守护线程
守护线程在后台运行,用于服务用户线程(非守护线程)。当所有用户线程结束时,守护线程自动退出。
通过 setDaemon(true)
将线程设置为守护线程。当主线程结束之后,守护线程不会立刻结束而是陆续结束。
public class Main {public static void main(String[] args) {Thread thread = new Thread(() -> {while (true) {System.out.println("Daemon thread running...");try {Thread.sleep(1000);} catch (InterruptedException e) {break;}}});thread.setDaemon(true); // 设置为守护线程thread.start();System.out.println("Main thread ends.");}
}
多线程的声明周期
同步代码块
使用 synchronized
确保同一时间只有一个线程访问共享资源。
注意在synchronized小括号里面的一般会是该类的字节码文件(类.class)必须保证其唯一性。
package Thread;// 三个窗口售卖票 总共有50张票
public class practice {public static void main(String[] args) {Myr myr = new Myr();Thread t1 = new Thread(myr);Thread t2 = new Thread(myr);Thread t3 = new Thread(myr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}class Myr implements Runnable {private int cnt = 1; // 初始票号设为 1// 同步代码块@Overridepublic void run() {while (true) {synchronized (Myr.class) {if (cnt > 50) break; // 先检查是否有票可卖System.out.println(Thread.currentThread().getName() + "正在售卖第 " + cnt + " 张票!");cnt++; // 售出当前票后再自增}try {Thread.sleep(100); // 模拟售票时间} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
同步方法
同步方法是锁住方法里面所有的代码,其实就是把同步代码块里面的代码提取成同步方法。
注意:同步方法锁的对象是不可以指定的。在java中,非静态的锁对象是this。静态的锁对象是本类的字节码文件对象(类.class)
package Thread;// 三个窗口售卖票 总共有50张票
public class practice {public static void main(String[] args) {Myr myr = new Myr();Thread t1 = new Thread(myr);Thread t2 = new Thread(myr);Thread t3 = new Thread(myr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}class Myr implements Runnable {private int cnt = 1; // 初始票号设为 1@Overridepublic void run() {while (true) {if (!method()) break;;}}
// 同步方法private synchronized boolean method() {if (cnt > 50) return false; // 先检查是否有票可卖System.out.println(Thread.currentThread().getName() + "正在售卖第 " + cnt + " 张票!");cnt++; // 售出当前票后再自增try {Thread.sleep(100); // 模拟售票时间} catch (InterruptedException e) {throw new RuntimeException(e);}return true;}
}
死锁
死锁就是两个锁嵌套,在以后写代码的时候需要注意不要写嵌套的锁
等待唤醒机制(线程协调)
在等待唤醒机制中,一般会将锁对象(通常是一个共享资源或
Object
)和线程操作关联起来。这是因为 wait()
、notify()
和 notifyAll()
方法必须在同步代码块或同步方法中调用,而这些同步需要一个明确的锁对象来协调线程间的通信。
代码中通过 Desk.lock.wait()
和 Desk.lock.notify()
有效地将线程等待与特定的锁对象关联起来。这样线程可以知道锁住和这个锁对象关联起来的线程,也可以唤醒与这个锁对象关联起来的线程
package waitandnotify;public class Desk {public static final Object lock = new Object(); // 锁对象public static int cnt = 5; // 剩余次数public static int foodFlag = 0; // 食物标志:0 - 无食物,1 - 有食物
}class Cook extends Thread {@Overridepublic void run() {while (true) {synchronized (Desk.lock) {if (Desk.cnt == 0) {break; // 没有剩余任务,结束线程}if (Desk.foodFlag == 1) {try {Desk.lock.wait(); // 有食物,等待消费者} catch (InterruptedException e) {e.printStackTrace();}} else if (Desk.foodFlag == 0) {// 生产食物System.out.println("厨师做了一碗面条");Desk.foodFlag = 1;Desk.lock.notify(); // 唤醒消费者}}}}
}class Consumer extends Thread {@Overridepublic void run() {while (true) {synchronized (Desk.lock) {if (Desk.cnt == 0) {break; // 没有剩余任务,结束线程}if (Desk.foodFlag == 0) {try {Desk.lock.wait(); // 没有食物,等待生产者} catch (InterruptedException e) {e.printStackTrace();}} else if (Desk.foodFlag == 1) {// 消费食物System.out.println("消费者吃了一碗面条");Desk.foodFlag = 0;Desk.cnt--; // 减少任务次数Desk.lock.notify(); // 唤醒生产者}}}}
}public class Main {public static void main(String[] args) {Cook cook = new Cook();Consumer consumer = new Consumer();cook.start();consumer.start();}
}
线程池
package Thread.Threadpool;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class MyThreadPool {public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(3, // 核心线程数量不能少于06, // 最大线程数量,不能小于0 最大线程数量大于等于核心线程60, // 临时线程60s就会销毁TimeUnit.SECONDS, // 时间单位new ArrayBlockingQueue<>(3), // 任务队列Executors.defaultThreadFactory(), // 创建线程工厂new ThreadPoolExecutor.AbortPolicy() //任务的拒绝策略);// 为什么任务的拒绝策略需要定义在类的内部类当中?//划重点:什么时候创建内部类,当一个类依赖另一个类存在时,而他单独存在没有意义时,// 就可以创建某个类的内部类pool.submit(new MyRunnable());}
}