线程间通信之wait和notify
synchronized
解释:java语言的一个关键字
作用:实现同步机制,控制多线程的访问,确保同一时刻只有一个线程可以进入临界区执行同步代码。
用法:加在代码块上、加在方法上、加在一个对象,
原理:不管是那种用法,都会有一个对象(指定的对象、class的实例对象、class对象),这个对象又会一一对应一个监视器对象,然后对监视器对象加锁,编译成字节码后,会有monitorenter和monitorexit标记同步代码块的入口和出口
监视器对象(ObjectMonitor)里有一些变量,记录一些信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ObjectMonitor() { _header = NULL; _count = 0 ; // 重入次数 _waiters = 0 , // 等待线程数 _recursions = 0 ; _object = NULL; _owner = NULL; // 当前持有锁的线程 _WaitSet = NULL; // 调用了 wait 方法的线程被阻塞 放置在这里 _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; // 等待锁 处于block的线程 有资格成为候选资源的线程 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; } |
wait
解释:是Object类的一个final方法,会抛出InterruptedException
作用:让当前线程进入等待状态,并释放持有的锁
原理:会将当前线程加入ObjectMonitor的_WaitSet,当前线程随即释放锁,并等待在原地,停止执行后续代码
用法:使用synchronized包裹,抛出或者处理中断异常
1 2 3 4 5 | public void doWait() throws InterruptedException { synchronized (obj) { obj.wait(); } } |
notify
解释:是Object类的一个final native方法
作用:随机唤醒一个线程,这个线程是waiting在当前object的monitor,即加入ObjectMonitor的_WaitSet的线程
原理:从ObjectMonitor的_WaitSet中随机取出一个线程唤醒,这个线程随即获取锁,继续执行后续的代码
用法:使用synchronized包裹
1 2 3 4 5 | public void doNotify() { synchronized (obj) { obj.notify(); } } |
notifyAll
同notify,只不过唤醒所有的等待线程,所有的等待线程随即竞争同步锁
下面是一个经典的生产者消费者模型,由于是多个生产者多个消费者,在此,在仓库满了以后,我们使用wait让生产者进入等待,在仓库空了以后让消费者进入等待。当生产者将商品放入仓库以后,通知等待的消费者继续消费 或者 当消费者消费了商品以后,通知等待的生产者继续生产,此处由于是多个生产者和多个消费者,如果使用nofity,可能唤醒的不是想要唤醒的线程。 但是使用notifyAll,需要做一个保护,下面代码中的while。 在仓库满了以后,如果唤醒的生产者竞争到了锁,还是会将商品放入了仓库,导致仓库爆了,或者 在仓库空了以后,如果唤醒的消费者竞争到了锁,会消费不到商品。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | public class Test { public static void main(String[] args) { new Test().start(); } private void start(){ Store store = new Store( 10 ); Thread producer1 = new Thread( new Producer( "producer1" ,store, 1000 )); Thread producer2 = new Thread( new Producer( "producer2" ,store, 1000 )); Thread consumer1 = new Thread( new Consumer( "consumer1" ,store, 1000 )); Thread consumer2 = new Thread( new Consumer( "consumer2" ,store, 1000 )); Thread consumer3 = new Thread( new Consumer( "consumer3" ,store, 1000 )); producer1.start(); producer2.start(); consumer1.start(); consumer2.start(); consumer3.start(); } class Store { final int capacity; final List<String> list; public Store( int capacity){ this .capacity = capacity; list = new ArrayList<>(capacity); } public String take() throws InterruptedException { synchronized (list) { while (list.isEmpty()) { // prevent consumer notify consumer, so use while list.wait(); } String product = list.remove(list.size() - 1 ); list.notifyAll(); return product; } } public void add(String product) throws InterruptedException { synchronized (list) { while (list.size() >= capacity) { // prevent producer notify producer, so use while list.wait(); } list.add(product); list.notifyAll(); } } } class Producer implements Runnable{ String flag; Store store; int interval; public Producer(String flag, Store store, int interval) { this .flag = flag; this .store = store; this .interval = interval; } @Override public void run() { for ( long i= 0 ;;i++) { try { Thread.sleep(interval); } catch (InterruptedException e) { System.out.println( "sleep InterruptedException so finish thread " +flag); break ; } String product = "product-" +flag+ "-" +i; System.out.println(flag+ " produce " +product); try { store.add(product); } catch (InterruptedException e) { System.out.println( "wait/notify InterruptedException so finish thread " +flag); break ; } } } } class Consumer implements Runnable{ String flag; Store store; int interval; public Consumer(String flag, Store store, int interval) { this .flag = flag; this .store = store; this .interval = interval; } @Override public void run() { for (;;) { try { Thread.sleep(interval); } catch (InterruptedException e) { System.out.println( "sleep InterruptedException so finish thread " +flag); break ; } try { String product = store.take(); System.out.println(flag+ " consume " +product); } catch (InterruptedException e) { System.out.println( "wait/notify InterruptedException so finish thread " +flag); break ; } } } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!