看完后,你再也不用怕面试问并发编程啦( 二 )


2、wait() 使当前线程阻塞,前提是必须先获得锁,一般配合synchronized 关键字使用 。   
即 , 一般在 synchronized 同步代码块里使用 wait()、notify、notifyAll() 方法 。
3、由于 wait()、notify()、notifyAll() 方法在 synchronized 代码块执行,说明当前线程一定是获取了锁的 。当线程执行wait()方法时候 , 会释放当前的锁,然后让出CPU,进入等待状态 。只有当 notify()/notifyAll() 被执行时候 , 才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完 synchronized 代码块的代码或是中途遇到wait() , 再次释放锁 。也就是说,notify()/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁 , 锁的释放要看代码块的具体执行情况 。所以在编程中,尽量在使用了 notify()/notifyAll() 后立即退出临界区,以唤醒其他线程让其获得锁 。
4、notify 和 wait 的顺序不能错 , 如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的 。
5、notify 和 notifyAll的区别:   

  • notify: 只唤醒一个等待(对象的)线程并使该线程开始执行 。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现 。      
  • notifyAll: 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现 。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll方法 。
代码:package cn.itcast.thread;import java.util.concurrent.TimeUnit;/** * 测试 wait()、notify()、notifyAll() */public class Test1 { public static void main(String[] args) { // 创建对象 Object obj = new Object(); // 线程t1 new Thread(() -> { synchronized (obj) { try { System.out.println(Thread.currentThread().getName() + "wait 前"); obj.wait(); // 等待、线程阻塞(释放锁) System.out.println(Thread.currentThread().getName() + "wait 后"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1:").start(); // 线程t2 new Thread(() -> { synchronized (obj) { try { System.out.println(Thread.currentThread().getName() + "wait 前"); obj.wait(); // 等待、线程阻塞(释放锁) System.out.println(Thread.currentThread().getName() + "wait 后"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t2:").start(); // 线程t3 new Thread(() -> { synchronized (obj) { try { // 休眠2秒 TimeUnit.SECONDS.sleep(2); //目的让前2个线程进入等待状态 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("notifyAll 前"); obj.notifyAll(); // 唤醒全部等待的线程,不会释放锁 System.out.println("notifyAll 后"); } }, "t3:").start(); } 小结
  • wait()方法的作用?
导致当前线程等待 。(释放锁,让出CPU)
  • notify()方法的作用?
唤醒正在等待的单个线程 。(不释放锁,不让出CPU)4、多线程编程:线程状态及状态转换目标:理解线程6种状态以及状态转换 。
线程状态
线程可以处于以下状态之一:
  • NEW 尚未启动的线程处于此状态 。
  • RUNNABLE 在Java虚拟机中执行的线程处于此状态 。
  • BLOCKED 被阻塞等待的线程处于此状态 。
  • WAITING 无限等待另一个线程执行特定动作的线程处于此状态 。
  • TIMED_WAITING 一个正在限时等待另一个线程执行一个动作的线程处于这一状态 。
  • TERMINATED 已退出的线程处于此状态 。
     Thread.State 枚举类中进行了定义 。
状态转换
看完后,你再也不用怕面试问并发编程啦

文章插图
代码:package cn.itcast.thread;/** 测试: 线程6种状态 */public class Test2 { // 方法1 (RUNNABLE: 运行) public static void test1() { new Thread(() -> { synchronized (Test2.class) { while (true) { } } }, "t1-runnable").start(); //线程运行中 } // 方法2 (TIMED_WAITING : 超时等待) public static void test2() { new Thread(() -> { synchronized (Test2.class) { while (true) { try { Test2.class.wait(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "t2-timed_waiting").start(); //线程超时等待中 } // 方法3 public static void test3() { // (RUNNABLE: 运行) new Thread(() -> { synchronized (Test2.class) { while (true) { } } }, "t3-runnable").start(); // (BLOCKED: 阻塞) new Thread(() -> { synchronized (Test2.class) { //由于上面没有释放锁,被阻塞中 } }, "t4-BLOCKED").start(); } // 方法4 (WAITING : 等待) public static void test4() { new Thread(() -> { synchronized (Test2.class) { while (true) { try { Test2.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "t5-waiting").start(); //线程等待中 } public static void main(String[] args) { //test1(); // 线程运行中 //test2(); // 线程超时等待中 test3(); // 线程阻塞中 //test4(); // 线程等待中 }}


推荐阅读