java基础加强学了多线程和等待唤醒机制,通过查阅API等资料,想实现多个生产者和多个消费者之间正确的通信,现以生产消费馒头为例,代码如下:
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProduceComsumerNew {
public static void main(String[] args) {
Mantou mantou = new Mantou();
new Thread(new Producer1(mantou,"红糖馒头"),"馒头铺1").start();
new Thread(new Producer1(mantou,"韭菜馒头"),"馒头铺2").start();
new Thread(new Producer1(mantou,"玉米馒头"),"馒头铺3").start();
new Thread(new Consumer1(mantou),"AAA").start();
new Thread(new Consumer1(mantou),"BBB").start();
new Thread(new Consumer1(mantou),"CCC").start();
}
}
//生产者
class Producer1 implements Runnable{
private Mantou mantou;
private String name;
Producer1(Mantou mantou,String name) {
this.mantou = mantou;
this.name = name;
}
@Override
public void run() {
while (true) {
//让线程争抢的能力下降
Thread.currentThread().setPriority(4);
mantou.produce(name);
//让线程恢复争抢能力
Thread.currentThread().setPriority(5);
}
}
}
//消费者
class Consumer1 implements Runnable {
private Mantou mantou;
Consumer1(Mantou mantou) {
this.mantou = mantou;
}
@Override
public void run() {
while (true) {
//让线程争抢的能力下降
Thread.currentThread().setPriority(4);
mantou.consume();
//让线程恢复争抢能力
Thread.currentThread().setPriority(5);
}
}
}
//产品
class Mantou {
//馒头名称
private String name;
//记录数量
private int count = 0;
//最大生产量
private int max = 5;
//创建一个容器放馒头
private ArrayList<Mantou> arrayList = new ArrayList<>(10);
//创建一把锁控制同步
private Lock lock = new ReentrantLock();
//创建和锁绑定的Condition对象,控制生产者
private Condition pro = lock.newCondition();
//创建和锁绑定的Condition对象,控制消费者
private Condition con = lock.newCondition();
public Mantou() {
}
public Mantou(String name) {
this.name = name;
}
//生产功能
public void produce(String name) {
lock.lock();
try {
//判断是否该生产
if (count == max) {
pro.await();
//防止线程唤醒后直接从此处往下执行,未找到最终原因。****************
pro.signal();
return;
}
arrayList.add(new Mantou(name));
System.out.println(Thread.currentThread().getName()+"生产了一个:"
+name+"包子,库存:"+(++count)+"个");
con.signalAll();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//消费功能
public void consume() {
lock.lock();
try {
//判断是否可以消费
if(count == 0) {
con.await();
//防止线程唤醒后直接从此处往下执行,未找到最终原因。****************
con.signal();
return;
}
Mantou m = arrayList.remove(0);
System.out.println(Thread.currentThread().getName()+"消费了一个:"
+m.name+"还剩:"+(--count)+"个");
pro.signalAll();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
最后打印结果为:
馒头铺2生产了一个:韭菜馒头包子,库存:1个
馒头铺2生产了一个:韭菜馒头包子,库存:2个
馒头铺1生产了一个:红糖馒头包子,库存:3个
馒头铺3生产了一个:玉米馒头包子,库存:4个
BBB消费了一个:韭菜馒头还剩:3个
BBB消费了一个:韭菜馒头还剩:2个
CCC消费了一个:红糖馒头还剩:1个
CCC消费了一个:玉米馒头还剩:0个
馒头铺2生产了一个:韭菜馒头包子,库存:1个
馒头铺2生产了一个:韭菜馒头包子,库存:2个
馒头铺2生产了一个:韭菜馒头包子,库存:3个
馒头铺2生产了一个:韭菜馒头包子,库存:4个
馒头铺1生产了一个:红糖馒头包子,库存:5个
BBB消费了一个:韭菜馒头还剩:4个
BBB消费了一个:韭菜馒头还剩:3个
AAA消费了一个:韭菜馒头还剩:2个
AAA消费了一个:韭菜馒头还剩:1个
AAA消费了一个:红糖馒头还剩:0个
。。。。。。
虽然程序跑了一段时间未出现问题,但多线程的实现需要考虑很多细节,否则无法保证永久不出错。比如代码中******结尾的注释下的代码,如果不加这一段逻辑则会出现当前线程被唤醒后直接往下执行(跳过if判断)的情况,如果有同学知道真正的细节,还请指出,谢谢。
|
|