这我们得实际开发当中,当遇到并发的应用时,我们总是需要设计一个这样的对象,该对象在多线程下被调用,而调用的这些方法都会改变对象自身的状态,为了避免竞争条件(race condition)的产生,对于这类对象的设计,需要考虑一下问题:
- 1、在任一时间内,只有唯一的公共方法被唯一的线程调用。
- 2、对于对象的调用者来说如果总是需要调用前加锁,调用结束后去锁,编程将会变得困难重重,正确的做法是该对象确保任何针对它的方法请求的同步被透明化,进而不需要调用者介入。
- 3、如果一个对象的方法执行过程中,由于某些条件不能满足而阻塞,应该允许其他的客户端线程的方法调用可以访问该对象。例如:生产者消费者模式,当消费者从任务队列中无法获取任务时,将会调用wait()方法阻塞自己,等待其他线程notify自己。
Monitor Object模式:将被客户端线程并发访问的对象定义为一个monitor对象。客户端线程只能通过monitor对象的同步方法使用monitor对象定义的服务。为了防止陷入竞争条件,任一时刻只能有一个同步方法被调用执行。每一个monitor对象包含一个monitor锁。被同步方法用于串行访问对象的状态和方法。此外,同步方法可以根据一个或多个与monitor对象相关的monitor conditions来决定在任何情况下挂起或恢复它们的执行。
Monitor Object 模式中,主要有四种类型的参与者:
- 1、监视者对象(Monitor Object):负责定义公共的接口方法,这些公共的接口方法将会在多线程的环境下执行。
- 2、同步方法:监视者对象中定义。为了防止竞争条件的产生,无论是多线程并发调用监视者对象方法,还是监视者对象拥有多个同步方法,在同一时间内,只能有监视者对象的一个同步方法被一个线程调用执行。
- 3、监视锁(Monitor Lock):每个监视者对象都会拥有一把监视锁
- 4、监视条件(Monitor condition):同步方法通过监视锁和监视条件来决定方法是否能够被执行、是否需要阻塞、是否重新执行。
执行序列图:
1、同步方法的调用和串行化。当客户端调用监视者的同步方法时需要获取其监视锁。当该监视者对象有其他同步方法正在执行,获取监视锁就不成功。此时,客户端线程将会被阻塞直到获取监视锁。当客户端线程获取到监视锁,将进入临界区,执行方法中的逻辑,一旦同步方法执行结束,监视锁将会被释放,目的是使其他的线程有机会使用监视者对象的同步方法服务。
2、同步方法挂起。如果调用同步方法的客户线程必须挂起或者有其他不能继续执行的原因,它能够在一个监视条件上等待,这将导致该客户线程暂时释放监视锁,并挂起在监事条件上。
3、监视条件通知。一个客户线程能有通知一个监视条件,目的是让一个先前挂起在一个监视条件上的线程恢复运行。
4、同步方法线程恢复。一旦一个先前被挂起在一个监视条件上的同步方法线程获取通知,它将会继续在先前等待的监视条件的电上执行。在被通知线程被允许恢复执行同步方法之前,监视锁将自动被获取。