并发的核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。
三种管程模型:java参考的是MESA模型
Hasen 模型、Hoare 模型和 MESA 模型的一个核心区别就是当条件满足后,如何通知相关线程。管程要求同一时刻只允许一个线程执行,那当线程 T2 的操作使线程 T1 等待的条件满足时,T1 和 T2 究竟谁可以执行呢?
Hasen 模型里面,要求 notify() 放在代码的最后,这样 T2 通知完 T1 后,T2 就结束了,然后 T1 再执行,这样就能保证同一时刻只有一个线程执行。
Hoare 模型里面,T2 通知完 T1 后,T2 阻塞,T1 马上执行;等 T1 执行完,再唤醒 T2,也能保证同一时刻只有一个线程执行。但是相比 Hasen 模型,T2 多了一次阻塞唤醒操作。
MESA 管程里面,T2 通知完 T1 后,T2 还是会接着执行,T1 并不立即执行,仅仅是从条件变量的等待队列进到入口等待队列里面。这样做的好处是 notify() 不用放到代码的最后,T2 也没有多余的阻塞唤醒操作。但是也有个副作用,就是当 T1 再次执行的时候,可能曾经满足的条件,现在已经不满足了,所以需要以循环方式检验条件变量。
java内置的synchronized就是一个管程模型
入口队列存放线程,临界区只允许同时最多一个线程运行。
共享变量也就是要保护的资源;
条件变量是wait()/notify()的条件。
同样,通过增加条件变量可以实现支持多个条件的并发编程,java提供了并发包的锁。模型思想都是管程的思想:
08 管程:并发编程的万能钥匙 这一节中,老师写的阻塞队列就是依据这个思想,不得不说老师的代码非常典型。
本节问题:wait() 方法,在 Hasen 模型和 Hoare 模型里面,都是没有参数的,而在 MESA 模型里面,增加了超时参数,你觉得这个参数有必要吗?
回答:毫无疑问,肯定是必要的。增加超时的作用,在等待了这些时间后,会自动唤醒,避免一直等待。当然,如果自己唤醒了,同样需要检查条件是否满足,不满足再次阻塞。