JAVA中的管程

什么是管程

java在1.5之前只提供了synchronized,wait,notfiy,notfiyAll3种实现并发的源语,他们实际上是管程的组成部分。

对应的英文是Monitor,他表示管理共享变量以及操作共享变量,使其支持并发的过程。

java的实现–MESA模式

在管程的发展史上出现过3中管程模型,Hasen、Hoare、MESA。java采用的是MESA模型

在并发变成领域,有俩大核心问题:互斥–一个共享资源同一时刻只能被一个线程访问;同步–即线程之间的通信、协作;

java的管程如何解决互斥问题

如果:

avator

管程将资源以及方法都封装起来,只允许一个线程通过管程哦方法调用该方法。

java的管程如何解决同步问题

利用之前提到的消息-通知机制来让线程之间协作见下面的一个BlockQueue的代码,请忽略业务代码:P

  1. enq的时候while判断队列是否满了,如果满了,notFull.await()阻塞当前线程;
  2. enq如果没满,添加对象,并且用notEmpty.single()通知deque停止阻塞;
  3. deq可以顺利执行出队列的操作;
  4. deq的时候while判断队列是否为空,如果为空,notEmpty.await()阻塞当前线程;
  5. deq如果不为空,poll对象,并且用notFull.single()通知enq停止阻塞;
  6. enq可以顺利执行队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class BlockQueue {
ReentrantLock lock = new ReentrantLock();

Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

private Queue queue = new LinkedList();
private int queSize = 10;

public BlockQueue(int queSize) {
this.queSize = queSize;
}

public void enq(Object o) {
lock.lock();
try {
//如果为慢noFull阻塞线程
while (queue.size() == queSize) {
notFull.await();
}

queue.add(o);
//添加成功通知deq停止阻塞
notEmpty.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}

public Object deque() {
lock.lock();
Object ret = null;
try {
//如果为空notEmpty阻塞线程
while (queue.size() == 0) {
notEmpty.await();
}
return queue.poll();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
} finally {
//出队列成功通知队列未满可以入队列
notFull.signal();
lock.unlock();
}
}
}

notify使用场景

上面用了notify类似的逻辑,之前提到过能用notifyAll尽量用notifyAll。那么什么时候用notify呢。需要同时满足下面3个条件

  1. 所有线程的等待条件一样
  2. 所有线程满足等待条件后的操作一样
  3. 只需要唤醒一个线程

结合上面的场景,都是队列queue;notify之后的操作都是queue入队或者出队;只需要唤醒一个线程入/出队

管程3中模型的区别

  1. Hasen:T1在wait之后,T2notify,notify必须在T2最后一条语句,执行完后T2终止,以此保证系统只有一个线程在运行。
  2. Hoare:T1在wait之后,T2notify,notify后T2堵塞,T1开始运行,T1运行完后唤醒T2,新能略差,因为多了一次T2的唤醒。
  3. MESA:T1在wait之后,T2notify,T1值是获取了可执行的可能,需要竞争获取锁才能执行,JAVA采用此种模型

所以在MESA中wait的标准写法如下,因为被noyify通知之后线程只是可能执行,有可能在执行时候线程又会不满足条件

1
2
3
4
5
while( 条件){
synchronized(objcet){
object.wait();
}
}