多线程面试题系列3_生产者消费者模式的两种实现方法
题目
生产者-消费者模式
题目:
写一个固定容量的同步容器,拥有put和get方法,以及getCount方法
能够支持2个生产者线程和10个消费者线程的阻塞调用
-
解法一:
使用wait和notify/notifyAll实现
需要注意的点:
因为一个生产者只能生产一个食物,所以要想满足所有消费者必须启用数量相等的生产者线程。
wait()方法必须由一个上锁的对象使用。
使用notifyALL()。
使用while配合wait()。
class Container {
private static final int SIZE = 10;
volatile static int count = 0;
Object o = new Object();
void put() {
synchronized(o) {
while (getCount() == SIZE) {
try {
o.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
count++;
System.out.println("Producer now!\t" + "AFTER ALL: " + getCount());
o.notifyAll();
}
}
void get() {
synchronized(o) {
while (getCount() == 0) {
try {
o.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
count--;
System.out.println("Consumer now!\t" + "AFTER ALL: " + getCount());
o.notifyAll();
}
}
int getCount() {
return count;
}
}
public class Question3 {
public static void main(String[] args) {
Container container = new Container();
for(int i = 0; i < 10; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
container.get();
}
});
thread.start();
}
try {
Thread.sleep(2000);
} catch(Exception e) {
e.printStackTrace();
}
for(int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
container.put();
}
});
thread.start();
}
}
}
- 解法二:
使用wait和notify/notifyAll实现
需要注意的点:
因为一个生产者只能生产一个食物,所以要想满足所有消费者必须启用数量相等的生产者线程。
await()方法必须由一个上锁的ReentrantLock对象使用。
使用while配合await()。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class Container1 {
volatile static int count = 0;
private static final int SIZE = 10;
ReentrantLock lock = new ReentrantLock();
Condition condition_get = lock.newCondition();
Condition condition_put = lock.newCondition();
void get() {
lock.lock();
while(getCount() == 0) {
try {
condition_get.await();
} catch(Exception e) {
e.printStackTrace();
}
}
count--;
System.out.println("Consumer now!\t" + "AFTER ALL: " + getCount());
condition_put.signalAll();
lock.unlock();
}
void put() {
lock.lock();
while(getCount() == SIZE) {
try {
condition_put.await();
} catch(Exception e) {
e.printStackTrace();
}
}
count++;
System.out.println("Producer now!\t" + "AFTER ALL: " + getCount());
condition_get.signalAll();
lock.unlock();
}
int getCount() {
return count;
}
}
public class Question3a {
public static void main(String[] args) {
Container1 container1 = new Container1();
for(int i = 0; i < 10; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
container1.get();
}
});
thread.start();
}
try {
Thread.sleep(2000);
} catch(Exception e) {
e.printStackTrace();
}
for(int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
container1.put();
}
});
thread.start();
}
}
}