需求:
一个固定容量的同步容器,拥有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--》消费者线程拿到锁执行
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
//生产者调用
7
public synchronized void put(T t){
8
while(lists.size() == MAX){//不断判断容器是否满,满了则等待
9
try{
10
this.wait();
11
}catch(InterruptException e){
12
e.printStackTrace();
13
}
14
}
15
lists.add(t);
16
++count;
17
this.notifyAll();//通知消费者线程进行消费
18
}
19
//消费者调用
20
public synchronized T get(){
21
while(lists.size() == 0){//不断判断容器是否为空,空了则等待
22
try{
23
this.wait();
24
}catch(InterruptException e){
25
e.printStackTrace();
26
}
27
}
28
T tmp = lists.removeFirst();
29
--count;
30
this.notifyAll();//通知生产者线程进行生产
31
return tmp;
32
}
33
34
//主线程
35
public static void main(String[] args){
36
MyContainer<String> container = new MyContainer<>();
37
//启动10个消费者线程
38
for(int i=0;i<10;i++){
39
new Thread(()->{
40
for(int j=0;j<5;j++){
41
System.out.println(c.get());//每个线程从容器中取5个对象
42
}
43
}, "消费" + i).start();
44
}
45
46
try{
47
TimeUtils.SECONDS.sleep(2);
48
}catch(InterruptException e){
49
e.printStackTrace();
50
}
51
52
//启动2个生产者
53
for(int i=0;i<2;i++){
54
new Thread(()->{
55
for(int j=0;j<25;j++) c.put(Thread.currentThread().getName() + " " + j);
56
}, "生产" + i).start();
57
}
58
}
59
}
方法二: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
}