Exchanger
类Exchanger的功能可以使2个线程之间传输数据,它比生产者/消费者模式使用的wait/notify要更加方便。
Exchanger(交换者)是一个用于线程间协作的工具类。它用于线程间的数据交换。
如果第一个线程先执行了exchanger方法,它会一直等待第二个线程也执行exchanger,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程产生的数据传递给对象。
第一个Demo
public class ExhcangerTest {
private static final Exchanger<String> exgr = new Exchanger<String>();
// 创建固定大小的线程池
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String A = "银行流水A";
System.out.println("A先睡一会");
TimeUnit.SECONDS.sleep(5);
System.out.println("A : " + exgr.exchange(A));
} catch (Exception e) {
e.printStackTrace();
}
}
});
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String B = "银行流水B";
System.out.println("B准备好了");
System.out.println("B : " + exgr.exchange(B));
} catch (Exception e) {
e.printStackTrace();
}
}
});
threadPool.shutdown();
}
}
输出结果:
A先睡一会
B准备好了
A : 银行流水B
B : 银行流水A
这个Demo可以看出,如果两个线程有一个线程没有到达exchange方法,则会一直等待下去,如果担心有特殊情况,想避免一直等待,
可以使用exchange(V x , long timeout , TimeUnit unit)设置最长等待时间。
方法exchange()阻塞的特性
Exchanger中的exchange()方法具有阻塞的特点,也就是此方法被调用后等待其他线程来读取数据,如果没有线程来读取数据,则一直阻塞下去。
我们通过一个Demo,来看下线程阻塞效果:
public class ThreadA extends Thread {
private Exchanger<String> exchanger;
public ThreadA(Exchanger<String> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
System.out.println("在线程A中得到线程B的值 = " + exchanger.exchange("中国人A"));
System.out.println("A end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<String>();
ThreadA a = new ThreadA(exchanger);
a.start();
System.out.println("main end");
}
}
输出结果:
可以看出,虽然main运行完毕,但ThreadA一直在线程阻塞中。
方法exchange()传递数据
ThreadA 与 ThreadB 之间互相传递数据
public class ThreadA extends Thread {
private Exchanger<String> exchanger;
public ThreadA(Exchanger<String> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
System.out.println("线程A得到线程B的值 = " + exchanger.exchange("中国人A"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ThreadB extends Thread {
private Exchanger<String> exchanger;
public ThreadB(Exchanger<String> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
System.out.println("线程B得到线程A的值 = " + exchanger.exchange("中国人B"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<String>();
ThreadA a = new ThreadA(exchanger);
ThreadB b = new ThreadB(exchanger);
a.start();
b.start();
}
}
输出结果:
从输出结果看,线程A与线程B互相传递了数据。
(看的有些云里雾里,后面找资料补全)
方法exchange(Vx,long timeout,TimeUnit unit)与超时
当调用exchange(V x,longtimeout,TimeUnit unit)方法后,在指定的时间内没有其他线程获取数据,则会出现超时异常。
public class ThreadA extends Thread {
private Exchanger<String> exchanger;
public ThreadA(Exchanger<String> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
try {
System.out.println("在线程A中得到线程B的值 = " + exchanger.exchange("中国人A", 5, TimeUnit.SECONDS));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<String>();
ThreadA a = new ThreadA(exchanger);
a.start();
System.out.println("main end");
}
}
输出结果:
以上,可以看到,5秒之后,因为没有其他线程调用,抛出超时异常。
小结:
类Semaphore的主要作用是限制并发执行的线程数量,它具有synchronized所不具备的强大功能,比如:
- 等待获取许可的同时加入等待时间
- 尝试是否可以持有锁这些扩展功能
Exchanger是线程间传输数据的方式之一,而且在传输的数据类型上并没有任何限制。