生产者消费者容器
写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
能够支持2个生产者线程以及10个消费者线程的阻塞调用
使用wait和notify/notifyAll来实现
方法一: 使用synchronized 方法
- 方法上使用synchronized 用 this.wait() this.notifyAll()
- 判断条件的时候使用while
- 因为notifyAll 可能是一个生产者唤醒另一个在等待的生产者
- 所以这种情况下,另一个等待的生产者需要重新判断一下情况
- 注意countDownLatch.await() 不是 wait()方法
public class thread_consumer_provider_01 {
private List<Integer> list = new ArrayList<>();
private volatile Integer count = 0;
CountDownLatch countDownLatch = new CountDownLatch(12);
private synchronized void put(Integer num) {
while (list.size() == Integer.MAX_VALUE) {
try {
this.wait();
} catch (Exception e) {
System.err.println(e);
}
}
list.add(num);
count++;
this.notifyAll();
}
private synchronized Integer get() {
while (list.size() == 0) {
try {
this.wait();
} catch (Exception e) {
System.err.println(e);
}
}
Integer num = list.remove(0);
count--;
this.notifyAll();
return num;
}
public static void main(String[] args) {
thread_consumer_provider_01 t = new thread_consumer_provider_01();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 10; j++) {
try {
t.put(j);
} catch (Exception e) {
System.err.println(e);
}
}
t.countDownLatch.countDown();
}).start();
}
for (int i = 0; i < 2; i++) {
new Thread(() -> {
for (int j = 0; j < 10; j++) {
try {
Integer integer = t.get();
System.out.println(integer);
} catch (Exception e) {
System.err.println(e);
}
}
t.countDownLatch.countDown();
}).start();
}
try {
t.countDownLatch.await();
} catch (Exception e) {
System.err.println(e);
}
System.out.println("list size is :" + t.count);
}
}
方法二: 使用Lock方法
• Condition conside = lock.newCondition() 可以创建一个线程等待队列分组
• provider.await() 让这个线程谁在这个线程等待队列里面
• consumer.signalAll() 唤醒这个队列中的所有线程
public class thread_consumer_provider_02 {
List<Integer> list = new ArrayList<>();
Integer count = 0;
Lock lock = new ReentrantLock();
Condition consumer = lock.newCondition();
Condition provider = lock.newCondition();
CountDownLatch countDownLatch = new CountDownLatch(15);
private void put(Integer num) {
lock.lock();
try {
while (list.size() == Integer.MAX_VALUE) { //如果线程数不变的情况下 可以用if
provider.await();
}
list.add(num);
count++;
consumer.signalAll();
} catch (Exception e) {
System.err.println(e);
}finally {
lock.unlock();
}
}
private Integer get(){
lock.lock();
Integer num = null;
try{
while (list.size() == 0){
consumer.await();
}
num = list.remove(0);
count--;
provider.signalAll();
}catch (Exception e){
}finally {
lock.unlock();
}
return num;
}
public static void main(String[] args) {
thread_consumer_provider_02 t = new thread_consumer_provider_02();
for (int i = 0; i < 12; i++) {
new Thread(() -> {
for (int j = 0; j < 12; j++) {
try {
t.put(j);
} catch (Exception e) {
System.err.println(e);
}
}
t.countDownLatch.countDown();
}).start();
}
for (int i = 0; i < 3; i++) {
new Thread(() -> {
for (int j = 0; j < 12; j++) {
try {
Integer integer = t.get();
System.out.println(integer);
} catch (Exception e) {
System.err.println(e);
}
}
t.countDownLatch.countDown();
}).start();
}
try {
t.countDownLatch.await();
} catch (Exception e) {
System.err.println(e);
}
System.out.println("list size is :" + t.count);
}
}
两种方法比较:
• synchronized 唤醒线程的方法有可能消费者唤醒消费者
• Lock condition 可以唤醒指定队列中的线程
• synchronized 悲观锁 锁升级 偏向锁
• lock 乐观锁(cas 预期值 实际值 期望值 aba 加版本)