线程间通信机制- wait/notify

当我们使用线程来同时运行多个任务时,可以通过使用锁(互斥)来同步两个任务的行为,从而使得一个任务不会干扰到另外一个任务,这解决的是线程间彼此干涉的问题,现在我们需要来解决线程间彼此协调的问题,也就是线程间通信问题。有以下几种线程间通信的方式。

1.wait和notify/notifyAll

可以借助于Object类提供的wait()、notify()、notifyAll()三个方法,这三个方法属于Object类。但这三个方法必须由同步监视器对象来调用,这可分为两种情况
①对于用synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中直接调用这三个方法。
②对于用synchronized修饰的同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用这三个方法。

需要注意的是notify()方法只能随机唤醒一个线程,如果要唤醒所有线程,请使用notifyAll()。

2.使用Lock和Condition

如果程序不用synchronized关键字来进行同步,而是用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能使用wait()、notify()、notifyAll()方法进行线程通信了。
使用Lock对象的方式,Java提供了一个Condition类来保持协调,使用Condition可以让那些已经得到Lock对象却无法继续执行的线程释放Lock对象,Condition对象也可以唤醒其他处于等待的线程。
Condition将同步监视器方法wait()、notify()、notifyAll()分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set)。在这种情况下,Lock替代了同步方法和同步代码块,Condition替代了同步监视器的功能。
Condition实例被绑定在一个Lock对象上。要获得特定Lock实例的Condition实例,调用Lock对象的newCondition()方法获得即可。Condition类提供了以下三个方法:
await():
signal():

signalAll():

3.使用阻塞队列(BlockingQueue)控制线程通信

Java5提供了一个BlockingQueue接口,虽然BlockingQueue也是Queue的子接口,但它的主要用途不是作为容器,而是作为线程同步的工具。
BlockingQueue具有一个特征:当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满则线程被阻塞。而消费者线程 在取元素时,如果该队列已空则该线程被阻塞。
程序的两个线程通过交替向BlockingQueue中放入元素、取出元素,即可很好地控制线程的通信。

4.使用管道流进行线程通信

通过输入/输出在线程间进行通信通常很有用。Java中对应的实现就是PipedWriter类和PipedReader类。这种使用管道来通信的模型可以看成是"生产者-消费者"问题的变种,这里的管道就是一个封装好的解决方案。管道基本上就是一个阻塞队列,它存在于引入阻塞队列之前的java版本中在实际开发中,很少会使用到管道流

总结:

1.线程间通信的几种方式?有什么区别?

2.阻塞队列的作用?有哪几种不同的实现版本?

猜你喜欢

转载自www.cnblogs.com/rouqinglangzi/p/9106298.html