生产者消费者问题
设计一个容器,有put和get方法和最大容量,能够让2个生产者,10个消费者同时阻塞调用。
涉及到线程间的协作,如wait和notify方法。
wait和notify是object类的两个方法,锁.wait() 相当于将当前持有锁的这个线程wait,锁.notify() 相当于通知阻塞的线程可以醒来竞争获得锁了。
需要注意的是 notify并不释放锁,只有代码运行完或者抛出异常才释放锁
代码如下:
public class TestMyContaine<T> {
private List<T> lists = new LinkedList<>(); // linkedList删除新增元素效率更高
private int MAX = 10; // 最大容量
private int count;
// 加上同步锁
public synchronized void put(T t) {
// 想一下这里为什么要用while,而不能用if
while (this.count == MAX){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
++ count;
// 唤醒所有wait的线程,因为notify只唤醒随机一个,不建议使用
this.notifyAll();
}
public synchronized T get(){
T t = null;
while (this.count == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.remove(0);
-- count;
this.notifyAll();
return t;
}
}
测试
但这个还有一点瑕疵:notifyAll()是唤醒所有阻塞的线程,但如果是消费者进行notify,那只需要唤醒所有阻塞的生产者就行了;同理生产者只需唤醒所有阻塞的消费者。
可使用ReentranLock解决
public class TestMyContaine2<T> {
private List<T> lists = new LinkedList<>(); // linkedList删除新增元素效率更高
private int MAX = 10; // 最大容量
private int count;
private Lock lock = new ReentrantLock();
// consumer,producer相当于2个单独的队列,调用其await时,将线程阻塞并放入对应这个队列
// 调用singleAll时,唤醒所有队列里的线程,竞争拿锁
private Condition consumer = lock.newCondition();
private Condition producer = lock.newCondition();
public void put(T t) {
lock.lock(); // 加锁
// 想一下这里为什么要用while,而不能用if
while (this.count == MAX){
try {
producer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
++ count;
consumer.signalAll();
lock.unlock();
}
public T get(){
T t = null;
try{
lock.lock();
while (this.count == 0){
try {
consumer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.remove(0);
-- count;
producer.signalAll();
}catch (Exception e){
}
finally {
lock.unlock();
}
return t;
}
}