try {
while (index == bullets.length) {
System.out.println(“pushBullet 弹夹已满进入等待。。。。。index=” + index);
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notify();//唤醒等待线程
bullets[index] = bullet;
index++;
}
//枪膛射出子弹
public synchronized Bullet shootBullet() {
try {
while (index == 0) {
System.out.println(“shootBullet 枪膛为空进入等待。。。。。index=” + index);
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notify();
index–;
return bullets[index];
}
}
/**
-
@author LHW
-
@date 2020/12/25.
-
Description:
-
《wait/notify实现生产者和消费者程序》
-
采用多线程技术,例如wait/notify,设计实现一个符合生产者和消费者问题的程序,
-
对某一个对象(枪膛)进
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
行操作,其最大容量是10颗子弹,
-
生产者线程是一个压入线程,它不断向枪膛中压入子弹,
-
消费者线程是一个射出线程,它不断从枪膛中射出子弹。
*/
public class ShootingMain {
public static void main(String[] args) {
Clip mClip = new Clip();
new PushThread(mClip).start();
new ShootThread(mClip).start();
}
static class PushThread extends Thread {
Clip mClip;
PushThread(Clip clip) {
mClip = clip;
}
@Override
public void run() {
super.run();
for (int i = 0; i < mClip.bullets.length; i++) {
Bullet bullet = new Bullet();
bullet.id = i;
mClip.pushBullet(bullet);
System.out.println(“PushThread 子弹压入枪膛。。。” + bullet.id);
//如果这里不执行睡眠等待 生产会压入所有子弹后执行消费线程的射出子弹
SleepTools.ms(1000);//睡眠一秒 阻塞生产线程 执行消费线程
}
}
}
static class ShootThread extends Thread {
Clip mClip;
ShootThread(Clip clip) {
mClip = clip;
}
@Override
public void run() {
super.run();
for (int i = 0; i < mClip.bullets.length; i++) {
Bullet bullet = mClip.shootBullet();
System.out.println(“ShootThread 子弹射出枪膛。。。” + bullet.id);
SleepTools.ms(1000);//睡眠一秒 阻塞消费线程 执行生产线程
}
}
}
}
结果输出
PushThread 子弹压入枪膛。。。0
ShootThread 子弹射出枪膛。。。0
shootBullet 枪膛为空进入等待。。。。。index=0
PushThread 子弹压入枪膛。。。1
ShootThread 子弹射出枪膛。。。1
shootBullet 枪膛为空进入等待。。。。。index=0
PushThread 子弹压入枪膛。。。2
ShootThread 子弹射出枪膛。。。2
PushThread 子弹压入枪膛。。。3
ShootThread 子弹射出枪膛。。。3
PushThread 子弹压入枪膛。。。4
ShootThread 子弹射出枪膛。。。4
shootBullet 枪膛为空进入等待。。。。。index=0
PushThread 子弹压入枪膛。。。5
ShootThread 子弹射出枪膛。。。5
PushThread 子弹压入枪膛。。。6
ShootThread 子弹射出枪膛。。。6
shootBullet 枪膛为空进入等待。。。。。index=0
PushThread 子弹压入枪膛。。。7
ShootThread 子弹射出枪膛。。。7
shootBullet 枪膛为空进入等待。。。。。index=0
PushThread 子弹压入枪膛。。。8
ShootThread 子弹射出枪膛。。。8
PushThread 子弹压入枪膛。。。9
ShootThread 子弹射出枪膛。。。9
总结
消费者/生产模式通常用于如下情景:
-
1.生产与消费共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
-
2.生产者没有生产产品前即资源为空时,消费者进入等待,否则通知消费者进行消费
-
3.消费者消费后要通知生产者已消费完,需要通知生产者进行生产产品以供消费
线程直接的协作
- 协作(等待 / 通知机制)情景
是指一个线程 A 调用了对象 User 的 wait()方法进入等待状态,而另一个线程 B
调用了对象User 的 notify()或者 notifyAll()方法,线程A 收到通知后从对象User 的wait()方法返回,进而执行后续操作。上述两个线程通过对象User来完成交互,而对象上的 wait()和 notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
- notify():
- 通知一个在对象上等待的线程,使其从wait方法返回,而返回的前提是该线程
获取到了对象的锁,没有获得锁的线程重新进入 WAITING 状态。
- notifyAll():
通知所有等待在该对象上的线程
- wait()
调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断
才会返回.需要注意,调用 wait()方法后,会释放对象的锁
- wait(long)
超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有
通知就超时返回
- wait (long,int)
-对于超时时间更细粒度的控制,可以达到纳秒
注意:
以上方法均是java.lang.Object类的方法;
都只能在同步方法或者同步代码块中使用,否则会抛出异常。
等待和通知的标准范式
等待方遵循如下原则
-
获取对象的锁
-
如果条件不满足,那么调用的对象的wait()方法,被通知后仍要检查条件
-
条件满足则执行对应的逻辑
synchronized(对象){
while(条件不满足){
对象.wait();
}
对应的处理逻辑
}
通知方遵循如下原则
-
获取对象的锁
-
改变条件
-
通知所有等待在对象上的线程