Exchanger用于两个线程之间进行数据交换,每个线程调用exchage方法到达各自的同步点,当且仅当两个线程都达到同步点的时候,才可以交换信息,否则先到达同步点的线程必须等待。
Exchanger仅可用作两个线程之间的信息交换,当超过2个线程调用同一个Exchanger时,得到的结果是不可预料的。
上面的话需要好好理解
(1)验证数据交换
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Exchanger;
public class ExchangerTest1 {
public static void main(String[] args) {
//初始化一个交换器
Exchanger<String> exchanger = new Exchanger<>();
List<String> tails1 = new ArrayList<>();
tails1.add("a");
tails1.add("b");
tails1.add("c");
List<String> tails2 = new ArrayList<>();
tails2.add("a");
tails2.add("d");
tails2.add("c");
new Thread(new Runnable() {
@Override
public void run() {
try {
for (String tail:tails1) {
String tail1 = exchanger.exchange(tail);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
for (String tail:tails2) {
String tail1 = exchanger.exchange(tail);
System.out.println(tail);
System.out.println(tail1);
if (tail.equals(tail1)){
System.out.println("账单没问题" + System.currentTimeMillis());
}else{
System.out.println("账单不对");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
运行日志如下:
a
a
账单没问题1662026332330
d
b
账单不对
c
c
账单没问题1662026332330
思路解释:有2个数组tails1和tails2,利用2个线程对比2个数组是否一致。2个线程通过Exchanger逐个交换数据进行对比验证,可以验证出第二个数字不一致。
(2)验证同步点等待
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Exchanger;
public class ExchangerTest1 {
public static void main(String[] args) {
//初始化一个交换器
Exchanger<String> exchanger = new Exchanger<>();
List<String> tails1 = new ArrayList<>();
tails1.add("a");
tails1.add("b");
tails1.add("c");
List<String> tails2 = new ArrayList<>();
tails2.add("a");
tails2.add("d");
tails2.add("c");
/*
new Thread(new Runnable() {
@Override
public void run() {
try {
for (String tail:tails1) {
String tail1 = exchanger.exchange(tail);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();*/
new Thread(new Runnable() {
@Override
public void run() {
try {
for (String tail:tails2) {
System.out.println("tail等待交换。。。。" + System.currentTimeMillis());
String tail1 = exchanger.exchange(tail);
System.out.println(tail);
System.out.println(tail1);
if (tail.equals(tail1)){
System.out.println("账单没问题" + System.currentTimeMillis());
}else{
System.out.println("账单不对");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
运行日志:
tail等待交换。。。。1662026718504
只有一个线程运行时,没有其他线程与之交换,因此没有同时达到同步点,会一直阻塞。就像一开始说的:先到达同步点的线程必须等待。
(3)阻塞可以设置一个时间限制,等待到一定时间抛出异常,如下验证
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ExchangerTest1 {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
List<String> tails1 = new ArrayList<>();
tails1.add("a");
tails1.add("b");
tails1.add("c");
List<String> tails2 = new ArrayList<>();
tails2.add("a");
tails2.add("d");
tails2.add("c");
new Thread(new Runnable() {
@Override
public void run() {
try {
for (String tail:tails2) {
System.out.println("tail等待交换。。。。" + System.currentTimeMillis());
//等待5秒
String tail1 = exchanger.exchange(tail,5, TimeUnit.SECONDS);
System.out.println(tail);
System.out.println(tail1);
if (tail.equals(tail1)){
System.out.println("账单没问题" + System.currentTimeMillis());
}else{
System.out.println("账单不对");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
System.out.println("等待交换超时。。。。" + System.currentTimeMillis());
e.printStackTrace();
}
}
}).start();
}
}
运行日志:
tail等待交换。。。。1662026956498
等待交换超时。。。。1662026961500
java.util.concurrent.TimeoutException
at java.util.concurrent.Exchanger.exchange(Exchanger.java:626)
at com.example.demo.thread.ExchangerTest1$1.run(ExchangerTest1.java:41)
at java.lang.Thread.run(Thread.java:748)
超时时间:(1662026961500-1662026956498)/1000=5,差不多就是5秒超时
可以得出结论,没有达到同步点,确实在阻塞。
(4)如果超过2个线程交换信息,可能会造成信息的错乱,A线程的数据会和C线程交换,而C又和B进行交换,显然是无法保证交换结果。此处不做代码验证。