java多线程回顾4:线程通信

1 、线程的协调运行

线程的协调运行有一个经典案例,即生产者和消费者问题。

假设有一个货架,生产者往货架上放货物,消费者从货架上取货物。

为了方便讲解,制定一个规则,生产者每放上一个货物,消费者就得取走一个货物。不允许连续放两次,也不允许连续取两次。

为了实现这个功能,可以使用wait()、notify()和notifyAll()三个方法。注意,这三个方法不属于Thread类,而是属于Object类,且必须由同步监视器对象调用。详细用法如下:

Ø对于使用synchronized 修饰的同步方法,因为默认实例(this)就是同步监视器对象,所以可以在同步方法中直接调用这三个方法。

Ø对于使用synchronized 修饰的同步代码块,同步监视器对象是synchronized 后括号里的对象,必须使用该对象调用这三个方法

这三个方法的作用如下:

Øwait():使当前线程等待,直到其他线程调用该同步监视器的notify()或notifyAll()来唤醒该线程。调用wait()的当前线程会释放对该同步监视器的锁定。

Ønotify():唤醒在此同步监视器上的单个线程,如果有多个线程在等待,则随机唤醒一个。被唤醒的线程会在当前线程释放对同步监视器的锁定后开始运行。

ØnotifyAll():唤醒在此同步监视器上的所有线程,其余和notify()相同。

货架代码如下:

public classShelf {

//是否有货物的标志,true :有;false :没有

private booleanflag ;

//放入货物的方法

public synchronized voidproduct(){

//flag 为假时表示没有货物,此时可放入货物

if(!flag ){

flag = true;

System. out.println(Thread. currentThread().getName()+”放入了货物。”);

notifyAll();

} else{

try{

wait();

} catch(InterruptedException e) {

e.printStackTrace();

//取走货物的方法

public synchronized voidcustom(){

//flag 为真时表示有货物,此时可取走货物

if(flag ) {

flag = false;

System. out.println(Thread. currentThread().getName()+”取走了货物。”);

notifyAll();

} else{

try{

wait();

} catch(InterruptedException e) {

e.printStackTrace();

生产者线程代码如下:

public classProducerThread implementsRunnable{

privateShelf shelf ;

publicProducerThread(Shelf shelf){

this.shelf = shelf;

@Override

public voidrun() {

//放十次货物

for(inti = 0; i < 10; i++) {

shelf .product();

消费者线程代码如下:

public classCustomerThread implementsRunnable{

privateShelf shelf ;

publicCustomerThread(Shelf shelf){

this.shelf = shelf;

@Override

public voidrun() {

//取十次货物

for(inti = 0; i < 10; i++) {

shelf .custom();

测试代码如下:

public classTestShelf {

public static voidmain(String[] args) {

Shelf shelf = newShelf();

ProducerThread producerThread = newProducerThread(shelf);

CustomerThread customerThread = newCustomerThread(shelf);

newThread(producerThread,”生产者1″).start();

newThread(producerThread,”生产者2″).start();

newThread(customerThread,”消费者”).start();

运行结果如下:

生产者1 放入了货物。

消费者取走了货物。

生产者1 放入了货物。

消费者取走了货物。

生产者2 放入了货物。

消费者取走了货物。

生产者1 放入了货物。

消费者取走了货物。

生产者1 放入了货物。

消费者取走了货物。

生产者2 放入了货物。

消费者取走了货物。

生产者2 放入了货物。

消费者取走了货物。

生产者2 放入了货物。

上例中启动了两个生产者一个消费者,可见生产和消费是交替进行的,满足生产者每放上一个货物,消费者就得取走一个货物的规则。

最后程序将阻塞,因为消费者比较少,生产者最后只能一直等消费者来取走货物。同时消费者取货物的次数也小于10次,因为有时取货时没货了。

2 、使用条件变量协调运行

如果不使用synchronized,而是使用Lock对象来保证同步,则不能使用wait()、notify()和notifyAll()这三个方法。此时可使用Condition类来实现协作。

Condition实例必须从Lock实例中获得,也有三个方法,如下:

Øawait():和wait()类似,使当前线程等待,直到被唤醒。相比wait(),await()有更多的变体,这个以后再说。

Øsignal():和notify()类似,唤醒当前Lock 对象上的单条线程。

ØsignalAll()和notifyAll()类似,唤醒当前Lock 对象上的所有线程。

生产者线程、消费者线程、测试代码和测试结果的代码跟上一节完全一样,这里只放出货架的代码。

货架的代码:

public classShelf {

//是否有货物的标志,true :有;false :没有

private booleanflag ;

//定义Lock 对象

private finalLock lock = newReentrantLock();

//获取Lock 对象对应的Condition 对象

private finalCondition condition =lock .newCondition();

//放入货物的方法

public voidproduct(){

lock .lock();

try{

//flag 为假时表示没有货物,此时可放入货物

if(!flag ){

flag = true;

System. out.println(Thread. currentThread().getName()+”放入了货物。”);

condition .signalAll();

} else{

condition .await();

} catch(Exception e) {

e.printStackTrace();

} finally{

lock .unlock();

//取走货物的方法

public synchronized voidcustom(){

lock .lock();

try{

//flag 为真时表示有货物,此时可取走货物

if(flag ) {

flag = false;

System. out.println(Thread. currentThread().getName()+”取走了货物。”);

condition .signalAll();

} else{

condition .await();

} catch(Exception e) {

// TODO: handle exception

e.printStackTrace();

} finally{

lock .unlock();

3 、使用管道流通信

线程之间使用管道流通信并不是最好的方式,通常推荐使用共享资源的方式交换信息。所以本节内容了解一下就好。

管道流有三种形式,分别是管道字节流(PipedInputStream 、PipedOutputStream)、管道字符流(PipedReader 、PipedWriter)和新IO的管道Channel(Pipe.SinkChannel 、Pipe.SourceChannel)。

使用步骤如下:

Ø创建输入管道输入流和管道输出流对象。

Ø使用管道输入流或管道输出流的connect 方法把输入流和输出流连接起来。

Ø将管道输入流、管道输出流分别传入两个线程

Ø线程使用各自的管道流通信

代码就不贴了

Original: https://www.cnblogs.com/bailiyi/p/5310639.html
Author: 百里弈
Title: java多线程回顾4:线程通信

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/684198/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球