并发(5)线程之间的协作

多个任务之间运行,除了资源互斥之外,还需要一起协作去解决某个问题。当任务协作时,关键问题是这些任务之间的握手。为了实现这种握手,我们使用了相同的基础特性:互斥。在互斥之上,我们为任务添加一种途径,使其自身挂起,直至某些外部条件发生变化。

21.5.1wait()与notifyAll()

当我们的某个任务需要等待某个条件才能继续往下执行的时候该如何处理?

a 线程sleep(),这时候对象锁并没有释放。

b 不断的进行for循环,这样的忙等待是一种不良的CPU周期使用方式。

更优雅的方式是wait()。它提供了一种在任务之间对活动同步的方式,可以等待某个条件发生变化,而改变这个条件超出了当前方法的控制能力。wait()执行后,线程被挂起,对象锁被释放。

wait()没有参数,将无限等待下去;wait(time),表示在此期间等待。

打破wait()的方法是notify()和notifyAll()。执行前必须拥有对象锁,否则抛出异常。执行notify()前,一定要先执行过wait(),否则会错失信号。

wait()、notify()、notifyAll()是Object对象的一部分,不是Thread的一部分。比如对象obj.wait()后,要想通知一定还要用obj对象,如obj.notify()。有点像信号需要作用在某个载体上。

21.5.2notify()与notifyAll()

这两个方法的作用是唤醒线程,区别在于notify()只会唤醒一个线程,而notifyAll()则会唤醒所有等待的任务。需要注意的是notifyAll()唤醒的是某个特定锁的所有等待线程,而不是所有锁的特定线程,比如obj1和obj2都有很多任务在wait(),当调用obj1.notifyAll()时,obj2的等待线程不会被唤醒。

21.5.3生产者与消费者

调用wait()的方法可以认为是消费者,它在等待通知去消费(执行);notify()的调用方是生产者。生产完成后通知消费者。

比如餐厅里面的服务员和厨师就是一种生产与消费的关系。初始的时候,厨师.wait(),服务员记好菜单后调用厨师.notify(),厨师开始做饭,此时服务员.wait();当厨师做好饭后,调用服务员.notify(),然后厨师.wait()。如此往复循环。

21.5.4生产者-消费者与队列

JDK提供一种阻塞队列,能够实现生产者-消费者的模式。java.util.consurrent.BlockingQueue接口就是这样的队列,无界队列实现方式LinkedBlockingQueue,有界队列实现方式ArrayBlockingQueue。

take()是取值,put()是放值。消费者通过while循环进行take(),如果队列里面没有值,则会阻塞执行;生产者在里面put()值。

21.5.5任务间使用管道进行输入/输出

Java提供线程功能的类库支持线程间进行通信。PipedWriter类允许任务向管道写,PipeReader类允许不同任务从同一管道中读取。

PipedReader的构造依赖PipedWriter对象。

点击去京东购买《Java编程思想(第四版)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值