多线程编程核心技术读书笔记(三):进程间通信

本文深入探讨线程通信机制,包括共享对象通信、忙等待、等待/通知机制等,并详细解析生产者/消费者模式及管道流的应用。同时,还介绍了如何避免信号丢失和假唤醒等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。
1、通过共享对象通信
在共享对象的变量里设置信号值;线程A和B必须获得指向一个MySignal共享实例的引用,以便进行通信。
2、忙等待(busy wait)
用sleep()和while(true)实现通信
3、等待/通知机制(wait/notify)
Java有一个内建的等待机制来允许线程在等待信号的时候变为非运行状态。java.lang.Object 类定义了三个方法,wait()、notify()和notifyAll()来实现这个等待机制。
一个线程一旦调用了任意对象的wait()方法,就会变为非运行状态,直到另一个线程调用了同一个对象的notify()方法。为了调用wait()或者notify(),线程必须先获得那个对象的锁。也就是说,线程必须在同步块里调用wait()或者notify()。
当一个线程调用一个对象的notify()方法,正在等待该对象的所有线程中将有一个线程被唤醒并允许执行(这个将被唤醒的线程是随机的,不可以指定唤醒哪个线程)。同时也提供了一个notifyAll()方法来唤醒正在等待一个给定对象的所有线程。
Wait();运行前需要得到监视器对象的锁,运行后会释放锁,进入blocked状态,允许其余线程进入该锁;
再运行需要再次获取锁;
Wait(long):等待某一时间,是否有线程对其唤醒,如果没有,则自动唤醒;
4、丢失的信号
为了避免信号丢失, 用一个变量来保存是否被通知过。在notify前,设置自己已经被通知过。在wait后,设置自己没有被通知过,需要等待通知。
5、假唤醒
线程有可能在没有调用过notify()和notifyAll()的情况下醒来。这就是所谓的假唤醒(spurious wakeups)
为了防止假唤醒,保存信号的成员变量将在一个while循环里接受检查,而不是在if表达式里。这样的一个while循环叫做自旋锁(校注:这种做法要慎重,目前的JVM实现自旋会消耗CPU,如果长时间不调用doNotify方法,doWait方法会一直自旋,CPU会消耗太大)。被唤醒的线程会自旋直到自旋锁(while循环)里的条件变为false。
留意wait()方法是在while循环里,而不在if表达式里。如果等待线程没有收到信号就唤醒,wasSignalled变量将变为false,while循环会再执行一次,促使醒来的线程回到等待状态。
6、多个线程等待相同信号
如果你有多个线程在等待,被notifyAll()唤醒,但只有一个被允许继续执行,使用while循环也是个好方法。每次只有一个线程可以获得监视器对象锁,意味着只有一个线程可以退出wait()调用并清除wasSignalled标志(设为false)。一旦这个线程退出doWait()的同步块,其他线程退出wait()调用,并在while循环里检查wasSignalled变量值。但是,这个标志已经被第一个唤醒的线程清除了,所以其余醒来的线程将回到等待状态,直到下次信号到来。
7、不要在字符串常量或全局对象中调用wait()
JVM/编译器内部会把常量字符串转换成同一个对象。这意味着,即使你有2个不同的MyWaitNotify实例,它们都引用了相同的空字符串实例。

在wait()/notify()机制中,不要使用全局对象,字符串常量等。应该使用对应唯一的对象。

生产者/消费者模式实现:
等待/通知模式最经典的案例就是“生产者/消费者”模式。
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

通过管道进行线程通信:字节流
管道流:pipeStream
PipedInputStream、PipedOutputStream
PipedReader、PipedWriter
通过管道进行线程通信:字符流

Join方法(之前总结过了)
类ThreadLocal的使用
每个线程中的共享变量:每个线程绑定自己的值(比喻成全局存放数据的盒子,盒子中可以存放每个线程的私有数据)(线程变量具有隔离性)
类ThreadLocal的使用
让子线程从父线程中取得值;

参考资料:http://ifeve.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值