一个生产者, 一个消费者, 生产一个消费一个
public class Demo7 {
private int number = 0;
public static void main(String[] args) {
Demo7 demo7 = new Demo7();
Runnable productor = () -> {
synchronized (demo7) {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
if (demo7.number != 0) {
demo7.wait(); // 等待状态, 释放锁
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("生产前: " + demo7.number + ", 生产后: " + ++demo7.number);
demo7.notify();
}
}
};
Runnable consumer = () -> {
synchronized (demo7) {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
if (demo7.number == 0) {
demo7.wait(); // 等待状态, 释放锁
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("消费前: " + demo7.number + ", 消费后: " + --demo7.number);
demo7.notify();
}
}
};
new Thread(productor).start();
new Thread(consumer).start();
}
}
问题:
只支持一个生产者, 一个消费者, 生产一个消费一个, 不支持多个生产者, 多个消费者
比如两个生产者, 第一个生产者第一次进入while循环但不会进入wait方法, 然后生产了一个, 调用notify方法, 由于没有进入等待的线程, 然后再次循环, number数量为1, 则进入到wait方法, 释放锁, 第一个生产者等待, 第二个生产者也会进入到wait方法, 释放锁, 第二个生产者等待, 此时两个生产者都执行到了wait方法那一步, 要是被唤醒, 肯定也是从这一步往后执行代码
接下来消费者第一次while循环发现number数量为1, 不会进wait方法, 消费掉1后, number为0, 并且notify唤醒了一个生产者线程, 消费者第二次进入while循环, 进入到wait方法, 释放锁, 消费者等待
此时唤醒的那个生产者继续生产, 生产1个, 然后notify唤醒一个线程, 若是这个唤醒的线程是另外一个生产者, 那么等当前这个生产者线程执行完, 另外个生产者又进行生产了一个, 就出问题了, 消费者也是一样的道理
多个生产者/消费者, 只要不超过最大数量生产就可以生产, 只要数量大于0消费者就可以消费
public class Demo8 {
private int number = 0;
private static final int MAX = 10;
private static final int MIN = 0;
public static void main(String[] args) {
Demo8 demo8 = new Demo8();
Runnable productor = () -> {
try {
while (true) {
synchronized (demo8) {
Thread.sleep(100);
while (demo8.number == MAX) {
demo8.wait();
}
System.out.println(Thread.currentThread().getName() + "生产前: " + demo8.number + ", 生产后: " + ++demo8.number);
demo8.notifyAll();
// if (demo8.number == MAX) {
// demo8.wait();
// } else {
// System.out.println(Thread.currentThread().getName() + "生产前: " + demo8.number + ", 生产后: " + ++demo8.number);
// }
// demo8.notifyAll();
}
}
} catch (Exception e) {
e.printStackTrace();
}
};
Runnable consumer = () -> {
try {
while (true) {
synchronized (demo8) {
Thread.sleep(100);
while (demo8.number == MIN) {
demo8.wait();
}
System.out.println(Thread.currentThread().getName() + "消费前: " + demo8.number + ", 消费后: " + --demo8.number);
demo8.notifyAll();
// if (demo8.number == MIN) {
// demo8.wait();
// } else {
// System.out.println(Thread.currentThread().getName() + "消费前: " + demo8.number + ", 消费后: " + --demo8.number);
// }
// demo8.notifyAll();
}
}
} catch (Exception e) {
e.printStackTrace();
}
};
new Thread(productor, "生产者1").start();
new Thread(productor, "生产者2").start();
new Thread(productor, "生产者3").start();
new Thread(productor, "生产者4").start();
new Thread(productor, "生产者5").start();
new Thread(productor, "生产者6").start();
new Thread(productor, "生产者7").start();
new Thread(productor, "生产者8").start();
new Thread(consumer, "消费者1").start();
new Thread(consumer, "消费者2").start();
new Thread(consumer, "消费者3").start();
new Thread(consumer, "消费者4").start();
}
}
问题:
这里使用while (demo8.number == MAX) 和 while (demo8.number == MIN) 进行判断而不是单if, 因为单if会造成, 下次唤醒, 直接调用下面代码了, 从而不会再次判断
注释中if-else也不使用的原因是, 使用外层while (true)判断, 会调用notifyAll方法, 这个不确定是唤醒哪个线程, 导致如果需要唤醒生产者, 一直调用notifyAll, 一直唤醒消费者…假设最后才唤醒生产者, 但是已经过了很久时间了, 效率问题, 可能最终也能正确结果, 但是使用while的话就只notifyAll一次, 不满足条件的线程, 直接再次wait了
比较合理生产者消费者模式
public class Demo9 {
public static void main(String[] args) {
DataOperator dataOperator = new DataOperator();
Runnable productor = () -> {
while (dataOperator.flag) {
try {
Thread.sleep(100);
dataOperator.putData(new Data(Thread.currentThread().getName() + ", data"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable consumer = () -> {
while (dataOperator.flag) {
try {
Thread.sleep(100);
dataOperator.getData();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(productor, "生产者t1").start();
new Thread(productor, "生产者t2").start();
new Thread(productor, "生产者t3").start();
new Thread(productor, "生产者t4").start();
new Thread(productor, "生产者t5").start();
new Thread(productor, "生产者t6").start();
new Thread(consumer, "消费者t1").start();
new Thread(consumer, "消费者t2").start();
}
}
class Data {
private String dataName;
public Data(String dataName) {
this.dataName = dataName;
}
public String getDataName() {
return dataName;
}
}
class DataOperator {
private static final int MAX = 10;
private static final int MIN = 0;
private List<Data> list = new LinkedList<>();
public volatile boolean flag = true;
public synchronized void putData(Data data) throws InterruptedException {
while (list.size() == MAX) {
this.wait();
}
list.add(data);
System.out.println("生产者" + Thread.currentThread().getName() + "生产一个, list.size(): " + list.size());
this.notifyAll();
}
public synchronized Data getData() throws InterruptedException {
while (list.size() == MIN) {
this.wait();
}
Data data = list.remove(0);
System.out.println("消费者" + Thread.currentThread().getName() + "消费一个, list.size(): " + list.size());
this.notifyAll();
return data;
}
}
ReentrantLock+Condition实现生产者消费者模式
/**
* 当前为边生产边消费模式, 即生产者一边生产, 一边唤醒消费者线程消费, 消费者一边消费, 一般唤醒生产者生产
*/
public class Demo10 {
private static final int MAX = 10;
private static final int MIN = 0;
private ReentrantLock lock = new ReentrantLock();
private List<Object> list = new LinkedList<>();
private Condition productorCondition = lock.newCondition();
private Condition consumerCondition = lock.newCondition();
public static void main(String[] args) {
Demo10 demo10 = new Demo10();
Runnable productor = () -> {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// lock到unlock方法中为一次执行, 只要出了unlock后, 就没持有锁了, 其他线程就可以争抢了
try {
demo10.lock.lock();
// 生产者要是满了, 就在这里等待
while (demo10.list.size() == MAX) {
System.out.println(Thread.currentThread().getName() + "进入了等待");
demo10.productorCondition.await();
}
demo10.list.add(new Object());
System.out.println(Thread.currentThread().getName() + ", 生产了一个元素, size: " + demo10.list.size());
// 生产完一个后, 就唤醒消费者线程, 仅仅是唤醒, 要是当前生产者还没生产满
// 那么接下来生产者和消费者和都可以拿到锁, 生产者拿到就生产, 消费者拿到就消费, 所以一般来说生产消费并行的
demo10.consumerCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
demo10.lock.unlock();
}
}
};
Runnable consumer = () -> {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
demo10.lock.lock();
while (demo10.list.size() == MIN) {
System.out.println(Thread.currentThread().getName() + "进入了等待");
demo10.consumerCondition.await();
}
demo10.list.remove(0);
System.out.println(Thread.currentThread().getName() + ", 消费了一个元素, size: " + demo10.list.size());
demo10.productorCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
demo10.lock.unlock();
}
}
};
new Thread(productor, "生产者1").start();
new Thread(productor, "生产者2").start();
new Thread(productor, "生产者3").start();
new Thread(consumer, "消费者1").start();
new Thread(consumer, "消费者2").start();
new Thread(consumer, "消费者3").start();
new Thread(consumer, "消费者4").start();
// new Thread(consumer, "消费者5").start();
// new Thread(consumer, "消费者6").start();
// new Thread(consumer, "消费者7").start();
// new Thread(consumer, "消费者8").start();
}
}
有错误请指出…共同进步!