一、synchronized实现
-
synchronized实现生产者-消费者模型
/** * 生成者消费者例子 * 两个线程:生产线程生产数据 消费线程消费数据 * 如果当前有数据,生产者线程等待 * 如果当前没数据,消费者线程等待 */ public class ProdConsumDemo { public static void main(String[] args) { Data data = new Data(); new Thread(()->{ for(int i = 0;i < 10;i++){ try { data.produceData(); } catch (InterruptedException e) { e.printStackTrace(); } } },"Prod").start(); new Thread(()->{ for(int i = 0;i < 10;i++){ try { data.consumData(); } catch (InterruptedException e) { e.printStackTrace(); } } },"Consum").start(); } } class Data{ private int num = 0; // 0表示无数据 1表示有数据 public synchronized void produceData() throws InterruptedException { if(num != 0){ //有数据 //生产者线程等待 this.wait(); //会释放锁 } num++; System.out.println(Thread.currentThread().getName()+"线程:=>" + num); this.notifyAll(); //唤醒其他所有线程 wait中的线程 } public synchronized void consumData() throws InterruptedException { if(num == 0){ //没有数据 //消费者线程等待 this.wait(); //会释放锁 } num--; System.out.println(Thread.currentThread().getName()+"线程:=>" + num); this.notifyAll(); //唤醒其他所有线程 wait中的线程 } }
上述代码 如果使用两个生产者 两个消费者 就会出现虚假唤醒问题。
三个关键点:synchronized、wait、notify。
-
线程虚假唤醒问题
按照官方文档上的说明。Object类中 wait方法的说明
把if判断改为while循环判断。
while(num != 0){
//有数据
//生产者线程等待
this.wait();
}
while(num == 0){
//没有数据
//消费者线程等待
this.wait();
}
二、Lock实现
-
Lock实现生产者-消费者模型
参考API说明
代码实现:
/**
* 生成者消费者例子 Lock实现
* 两组线程:生产线程生产数据 消费线程消费数据
* 如果当前有数据,生产者线程等待
* 如果当前没数据,消费者线程等待
*/
public class ProdConsumDemoLock {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{
for(int i = 0;i < 10;i++){
try {
data.produceData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Prod1").start();
new Thread(()->{
for(int i = 0;i < 10;i++){
try {
data.produceData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Prod2").start();
new Thread(()->{
for(int i = 0;i < 10;i++){
try {
data.consumData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Consum1").start();
new Thread(()->{
for(int i = 0;i < 10;i++){
try {
data.consumData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Consum2").start();
}
}
class Data2{
private int num = 0; // 0表示无数据 1表示有数据
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void produceData() throws InterruptedException {
lock.lock();
try {
//使用while循环 防止虚假唤醒问题
while (num != 0) {
//有数据
//生产者线程等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName() + "线程:=>" + num);
//唤醒其他所有线程
condition.signalAll();
}
catch (Exception e){}
finally {
lock.unlock();
}
}
public void consumData() throws InterruptedException {
lock.lock();
try{
//使用while循环 防止虚假唤醒问题
while(num == 0){
//没有数据
//消费者线程等待
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+"线程:=>" + num);
//唤醒其他所有线程
condition.signalAll();
}
catch (Exception e){}
finally {
lock.unlock();
}
}
}
上面代码随机输出。
Lock实现3要素: lock、await、signalAll。
三、Condition实现3条线程顺序执行
-
使用Condition的精准通知实现
-
代码实现
/** * 通过Condition的线程精准唤醒 * 实现3条线程循环执行 * A->B->C->A->B... */ public class ConditionDemo { public static void main(String[] args) { Data3 data3 = new Data3(); new Thread(()->{ for (int i = 0; i < 10; i++) { data3.printA(); } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { data3.printB(); } },"B").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { data3.printC(); } },"C").start(); } } class Data3{ private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); private Condition conditionC = lock.newCondition(); private int num = 1; public void printA(){ lock.lock(); try { while(num != 1) conditionA.await(); //线程A等待 System.out.println(Thread.currentThread().getName()+"->AAAAAA"); num = 2; //唤醒线程B conditionB.signal(); } catch (Exception e){} finally { lock.unlock(); } } public void printB(){ lock.lock(); try { while(num != 2) conditionB.await(); //线程B等待 System.out.println(Thread.currentThread().getName()+"->BBBBBB"); num = 3; //唤醒线程C conditionC.signal(); } catch (Exception e){} finally { lock.unlock(); } } public void printC(){ lock.lock(); try { while(num != 3) conditionC.await(); //线程A等待 System.out.println(Thread.currentThread().getName()+"->CCCCCC"); num = 1; //唤醒线程A conditionA.signal(); } catch (Exception e){} finally { lock.unlock(); } } }