(新思路)生产者消费者模型(condition的解决方法)

来源:互联网 发布:c罗皇马 知乎 编辑:程序博客网 时间:2024/06/07 08:03
需求:
一个固定容量的同步容器,拥有put和get方法,还有getCount方法
能够支持两个生产者和10个消费者线程的阻塞调用
使用wait和notify/notifyAll实现

方法一:wait和notify的方法
思考:
1.第8行和第21行为什么用while不用if?
    生产者1和生产者2判断满了---》wait---》消费者消费了一个---》生产者1继续执行,add了一个对象又满了----》生产者2从while继续执行(再次判断是否满),再决定是否add。(如果用if,生产者2唤醒后不判断是否满了,直接add,list会溢出

2.第17行和第31行为什么用notifyAll不用notify?  
    如果用notify,生产者满了--》wait----》只唤醒一个线程,不小心唤醒了生产者,继续wait---》没有其它线程被唤醒---》死锁
    如果用notifyAll,生产者满了--》wait---》唤醒所有线程,如果唤醒的还是生产者,继续wait--》消费者线程拿到锁执行
方法二:lock和condition方法
可以精确控制唤醒生产者还是消费者线程
1
public class MyContainer<T>{
2
    final private LinkedList<T> lists = new LinkedList<>();
3
    final private int MAX = 10;//容量为10
4
    private int count = 0;
5
    
6
    private Lock lock = new ReentrainLock();
7
    private Condition producer = lock.newCondition();//生产者条件
8
    private Condition consumer = lock.newCondition();//消费者条件
9
    
10
    //生产者调用
11
    public void put(T t){
12
        try{
13
            lock.lock();//上锁
14
            while(lists.size() == MAX){//不断判断容器是否满,满了则等待
15
                producer.await();
16
            }
17
            
18
            lists.add(t);
19
            ++count;
20
            consumer.signalAll();//通知消费者线程进行消费
21
        }catch(InterruptException e){
22
            e.printStackTrace();
23
        }finally{
24
            lock.unlock();
25
        }
26
        
27
    }
28
    //消费者调用
29
    public T get(){
30
        
31
            try{
32
                lock.lock();//上锁
33
                while(lists.size() == 0){//不断判断容器是否为空,空了则等待
34
                    consumer.await();
35
                }
36
                T tmp = lists.removeFirst();
37
                --count;
38
                producer.signalAll();//通知生产者线程进行生产
39
                
40
            }catch(InterruptException e){
41
                e.printStackTrace();
42
            }finally{
43
                lock.unlock();
44
            }
45
        
46
        
47
        return tmp;
48
    }
49
    
50
    //主线程
51
    public static void main(String[] args){
52
        MyContainer<String> container = new MyContainer<>();
53
        //启动10个消费者线程
54
        for(int i=0;i<10;i++){
55
            new Thread(()->{
56
                for(int j=0;j<5;j++){
57
                    System.out.println(c.get());//每个线程从容器中取5个对象
58
                }
59
            }, "消费" + i).start();
60
        }
61
        
62
        try{
63
            TimeUtils.SECONDS.sleep(2);
64
        }catch(InterruptException e){
65
            e.printStackTrace();
66
        }
67
        
68
        //启动2个生产者
69
        for(int i=0;i<2;i++){
70
            new Thread(()->{
71
                for(int j=0;j<25;j++) c.put(Thread.currentThread().getName() + " " + j);
72
            }, "生产" + i).start();
73
        }
74
    }
75
}

阅读全文
1 0
原创粉丝点击