两个线程可以通过Exchanger来交换数据,从而将自己的状态告诉对方。
它是一个泛型类Exchanger<V>
,泛型参数表示交换数据的类型。
它定义了两个版本的exchange()
方法,分别是:
V exchange(V objRef) throws InterruptedException
V exchange(V objRef, long wait, TimeUnit tu) throws InterruptedException, TimeoutException
第一个版本的exchange()
方法将自己要交换的数据作为参数传递,返回值是另一个线程要交换的数据。第二个版本设置一个挂起的时间,如果超过指定时间没有受到另一个线程的数据的话,则会抛出TimeoutException
异常。一个线程调用exchange()
方法后挂起等待另一个线程也调用exchange()
方法,当另一个线程也调用该方法后,两个线程同时激活并完成数据交换,然后继续运行。
下面看一个例子:主线程启动了一个worker thread来做一件比较耗时的事情,但worker thread会一直向主线程报告当前进度,两个线程通过Exchanger
类来实现数据的交换。首先看worker thread的代码
import java.util.concurrent.Exchanger;
public class MyWorker implements Runnable {
Exchanger<Integer> exchanger;
public MyWorker(Exchanger<Integer> exchanger) {
this.exchanger = exchanger;
new Thread(this).start();
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
exchanger.exchange(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
它通过exchanger.exchange(i)
来报告自己的当前进度。线程不断地休眠是为了表示这个工作比较耗时。
下面是主线程的代码
public class ExchangerDemo {
public static void main(String[] args) throws InterruptedException {
Exchanger<Integer> exchanger = new Exchanger<>();
new MyWorker(exchanger);
int progress = exchanger.exchange(0);
while (progress < 100) {
System.out.println("progress: " + progress);
progress = exchanger.exchange(0);
}
System.out.println("complete");
}
}
主线程实例化了一个Exchanger<Integer>
对象,因为要交换的数据(当前进度)是一个数字,随后它通过new MyWorker(exchanger)
启动了该线程,并传递了用于通信的Exchanger对象。worker thread启动之后,主线程不停的通过exchanger.exchange(0)
挂起自己来获取worker thread的工作进度并打印出来,直到进度等于100后结束。
在这个例子中,由于主线程并不向worker thread发送数据,所以就随便写了个参数(这里传递了个0),而worker thread也没有接收来自主线程的数据。其实主线程可以通过发送一个特殊的code(如-1)来通知worker thread来取消任务,Exchanger类提供了这种线程间通信的能力,至于怎么使用,就要结合具体的场景了。