Java并发编程的艺术学习笔记(五)

Java并发编程基础(二)——线程间通信

1. synchronized和volatile关键字

1.1 实现线程间通信的原理

这种通信方式是利用volatile和synchronized的同步机制通过读/写共享变量来实现线程间通信的。当一个共享变量被修改后,同步机制能使其被其他线程看到,就好像一个线程把修改后的共享变量的值告诉另一个线程,这便在逻辑上实现了线程间的通信。

1.2 特点

这种通信方式无法指定接收线程,因为当共享变量被修改后,最先访问的另一线程的选择是随机的。总的来说,这种通信方式并不传送数据,而是在共享数据。

2. 等待/通知机制

2.1 等待/通知的相关方法

方法名称 作用
wait() 调用该方法的线程将进入线程的等待状态,只有等待另外线程的通知或中断才能从该方法返回。此外,调用该方法后会释放对象锁
wait(long) 该方法是wait()方法的超时等待版本。即在long毫秒时间内作用和wait()方法一致,在超过long时间后若还没被通知或中断,则直接返回。
notify() 通知另外一个在对象上等待的线程,令其从wait()方法返回。调用该方法的线程需先获得对象锁。
notifyAll() 通知另外所有在对象上等待的线程,令他们从wait()方法返回。调用该方法的线程需先获得对象锁。

2.2 等待/通知机制的理解

等待通知机制,是指一个线程A调用了某一对象O的wait()方法后进入线程的等待状态。另外一个线程B调用了对象O的notify()或notifyAll()方法后,线程A从wait()方法返回。上述两个线程是通过同一个对象O来实现交互的。

2.3 等待/通知机制的注意事项

●调用wait()、notify()或notify()方法前需先获得对象的锁。

●调用wait()方法的线程将进入线程的等待状态,并且被放置到等待队列中,同时释放对象锁。

●另一线程调用notify()方法后,等待队列中的一个线程将由等待状态转变为阻塞状态,并且被移动到同步队列中。同理notifyAll()方法操作的是等待队列中所有的线程。

●当线程调用notify()或notifyAll()方法后,另一线程并不会立即从wait()方法返回,而是需要调用notify()或notifyAll()的线程释放对象锁后才有机会从wait()方法返回。

●从wait()方法返回的前提是获得对象锁。

2.4 等待/通知机制的经典范式

●等待方:

synchronized(对象O) {
    while(条件不成立) {
        O.wait();
    }
    相应的处理逻辑;
}
复制代码

●通知方:

synchronized(对象O) {
    修改条件使得上述等待方的条件成立;
    O.notify()或O.notifyAll();
}
复制代码

3. 管道输入/输出流

●管道输入/输出流主要用处线程之间的数据传输,而传输的媒介为内存。

●管道输入/输出流的四种实现:PipedInputstream、PipedOutputStream、PipedWriter、PipedReader。前两种面向字节,后两种面向字符。

●管道的输入流和输出流在使用时需要进行连接,也就是调用connect()方法,否则会抛出IOException异常。

4. Thread.join()的使用

●当一个线程A执行了thread.join()时(底层调用wait()方法),表示让线程A等待线程thread执行完毕后再从join()方法返回线程A继续执行。

●除了join()方法外,还有join(long millis)和join(long millis,int nanos)这两个具备超时返回特性的方法。

●join()能让多条并发执行的线程串行执行。

●因调用join()方法而处于等待状态的线程可被其Thread.interrput()方法中断。

猜你喜欢

转载自juejin.im/post/5ce8ea8ef265da1bc07e14f1