一、sleep() 与 wait()
两者都会让当前线程进入等待状态。唤醒后都需要等待 CPU 资源,不一定会立即执行。若在等待期间被调用此线程的的 interrupt() 方法,将会产生 InterruptedException 异常。
wait() 是 Object 类的方法,会释放对象锁,并让出 CPU 资源。只能在 synchronized 下使用,使用 notify() 或 notiftAll() 唤醒。
// 线程工厂,这里主要用来设置线程名字 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build(); // 创建线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(6, 6, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); Object object = new Object(); threadPool.execute(() -> { try { synchronized (object) { object.wait(); System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAA"); } } catch (InterruptedException e) { e.printStackTrace(); } }); threadPool.execute(() -> { synchronized (object) { System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBB"); object.notify(); } });
sleep() 是 Thread 类的静态方法,只会让出 CPU 资源。可以使低优先级的线程得到执行的机会。
// 线程工厂,这里主要用来设置线程名字 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build(); // 创建线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(6, 6, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); threadPool.execute(() -> { try { // 阻塞 1 秒 Thread.sleep(1000); System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAA"); } catch (InterruptedException e) { e.printStackTrace(); } }); threadPool.execute(() -> { System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBBB"); });
两个示例都保证了 B 会在 A 之前被打印
二、notify() 与 notifyAll()
与 wait() 配合使用。两者都会唤醒其他线程,且会释放对象锁,不会阻塞当前线程。
其中 notify() 只唤醒等待线程当中的一个,notifyAll() 会唤醒所有等待线程。
notify() 是随机唤醒的,不同的 JDK 版本,在等待队列中唤醒的线程,其位置在等待队列中不同。
JDK1.8 中 notify() 唤醒的是等待队列中的头节点,即等待时间最长的那个线程。
唤醒的线程为同一个对象锁的线程。唤醒一个或所有,都只有一个线程会获取到锁对象。
三、yield() 与 join()
yield() 是 Thread 类的静态原生 (native) 方法,作用是让出 CPU 资源,不会阻塞当前线程,但可能让出 CPU 资源后,系统重新调度后又会选择给该线程 CPU 资源。使用场景比较少。
join() 是Thread 类实例的方法,可以使得一个线程在另一个线程结束后再执行。当前运行的线程将进入到等待状态直到另一个线程执行完成。
Thread t1 = new Thread(){ @Override public void run() { try { Thread.sleep(1000); System.out.println("A"); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t2 = new Thread(){ @Override public void run() { try { t1.join(); System.out.println("B"); } catch (InterruptedException e) { e.printStackTrace(); } } }; t2.start(); t1.start();
示例中保证了 A 在 B 之前被打印
四、interrupt()
中断等待状态的线程,并抛出异常。相关方法有三个。
interrupt() 是 Thread 类实例的方法,给线程中断状态设置为 false,等线程进入到等待状态时就会被中断,并抛出异常
isInterrupted() 是 Thread 类实例的方法,检测线程的中断状态
interrupted() 是 Thread 类的静态方法,实质调用的是 currentThread().isInterrupted(true),作用是检测线程的中断状态,然后将状态设置为 true
Thread t1 = new Thread() { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + "启动后的中断状态:" + Thread.currentThread().isInterrupted()); Thread.currentThread().interrupt(); System.out.println(Thread.currentThread().getName() + "interrupt()后的中断状态:" + Thread.currentThread().isInterrupted()); System.out.println(Thread.currentThread().getName() + "isInterrupted()获取中断状态:" + Thread.interrupted()); System.out.println(Thread.currentThread().getName() + "interrupted()后的中断状态:" + Thread.currentThread().isInterrupted()); Thread.currentThread().interrupt(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); System.out.println(Thread.currentThread().getName() + "异常时中断状态:" + Thread.interrupted()); } } }; new Thread() { @Override public void run() { System.out.println(t1.getName() + "未启动时的中断状态:" + t1.isInterrupted()); System.out.println("======================================================="); t1.start(); try { t1.join(); System.out.println("======================================================="); System.out.println(t1.getName() + "执行完时的中断状态:" + t1.isInterrupted()); } catch (InterruptedException e) { e.printStackTrace(); } } }.start();
https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html