The big anatomy of Exchanger:
This thing is a data exchange thread that exchanges data in this exchange as shown in the figure
The data of thread 1 waits for the arrival of the data of thread 2 in the switch (Exchanger) for data exchange
The condition of the exchange is that there are multiple pairs of threads that can be exchanged at the same time.
code demo
Prepare Thread A
//线程A
class ExchangerA extends Thread{
//保证同一个交换器
private Exchanger<String> exchanger =null;
public ExchangerA (Exchanger exchanger){
this.exchanger=exchanger;
}
public void run(){
System.out.println("这里是A线程"+Thread.currentThread().getName());
try {
Thread.sleep(3000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A的数据这边和B的数据准备进行交换");
try {
String s = exchanger.exchange("这是A的数据为11111");
System.out.println("这是在A现场里交换回来B的信息为"+s);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A和B交换完成继续干活");
}
}
Prepare thread B
//线程B
class ExchangerB extends Thread{
//保证同一个交换器
private Exchanger<String> exchanger =null;
public ExchangerB (Exchanger exchanger) {
this.exchanger = exchanger;
}
public void run(){
System.out.println("这里是B线程"+Thread.currentThread().getName());
try {
Thread.sleep(3000l);
System.out.println("B准备完成等待交换数据");
String ss = exchanger.exchange("这是B的数据为222");
System.out.println("这是在B线程里A的数据为"+ss);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A和B数据交换完成进行接下来的工作");
}
}
start test
public class ExchangerCS {
public static void main(String[] args) {
Exchanger<String> stringExchanger = new Exchanger<>();
new ExchangerA(stringExchanger).start();
new ExchangerB(stringExchanger).start();
}
}
Source code analysis of the core method in Exchanger
When we create a new Exchanger, we will declare the type in the generic type, and this generic type cannot exchange data between Exchangers. We give a generic type to the Exchanger, and then it uses the node node to receive and exchange our types uniformly. node node exchange
The position of the item is where the thread A data is placed
match is the data location to be exchanged with A thread in the future
Parked is the first thread to wait here
The core method of Exchanger
exchanger.exchange
The general meaning is that when the first thread brings data in, it will first judge whether it is a single-slot exchange or a multi-slot exchange.
Use slotExchange for a single slot
Multi-slot walk arenaExchange
Take the single slot method here
private final Object slotExchange(Object item, boolean timed, long ns) {
//线程A先进来拿到当前带来的node1数据
Node p = participant.get();
//获取到当前的线程A
Thread t = Thread.currentThread();
//判断线程A状态是否中断
if (t.isInterrupted()) // preserve interrupt status so caller can recheck
return null;
for (Node q;;) {
//判断单槽位节点的值是不是为空
if ((q = slot) != null) {
if (U.compareAndSwapObject(this, SLOT, q, null)) {
Object v = q.item;
//线程B的值就放到线程A的match里面
q.match = item;
Thread w = q.parked;
if (w != null)
//唤醒线程A
U.unpark(w);
return v;
}
// create arena on contention, but continue until slot null
if (NCPU > 1 && bound == 0 &&
U.compareAndSwapInt(this, BOUND, 0, SEQ))
arena = new Node[(FULL + 2) << ASHIFT];
}
else if (arena != null)
return null; // caller must reroute to arenaExchange
else {
//代码逻辑先到这里把线程A带来的数据值给了node1里面的item里面
p.item = item;
//这里让slot有了值 slot槽点就不为null
if (U.compareAndSwapObject(this, SLOT, null, p))
break;
p.item = null;
}
}
// await release
//下面是拿到当前节点的hash值去计算一些条件
int h = p.hash;
long end = timed ? System.nanoTime() + ns : 0L;
int spins = (NCPU > 1) ? SPINS : 1;
Object v;
//优化的操作 不用太了解
while ((v = p.match) == null) {
if (spins > 0) {
h ^= h << 1; h ^= h >>> 3; h ^= h << 10;
if (h == 0)
h = SPINS | (int)t.getId();
else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
Thread.yield();
}
//优化的操作 配对的线程到了还没有准备好 不用太了解
else if (slot != p)
spins = SPINS;
//
else if (!t.isInterrupted() && arena == null &&
(!timed || (ns = end - System.nanoTime()) > 0L)) {
U.putObject(t, BLOCKER, this);
//给这个node节点的park记下当前的线程
p.parked = t;
if (slot == p)
U.park(false, ns);
p.parked = null;
U.putObject(t, BLOCKER, null);
}
else if (U.compareAndSwapObject(this, SLOT, p, null)) {
v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
break;
}
}
U.putOrderedObject(p, MATCH, null);
p.item = null;
p.hash = h;
return v;
}
simple diagram
It is better to look at the source code step by step and click in to see it is more useful
P: The node data brought by the thread into the Exchanger
slot: single-slot node (generally the value of the first thread entering the Exchanger is null)
q: q is similar to slot, it will replace slot and assign null to slot
item: save the data brought by the thread
Match: save the exchanged data
parked: save the current thread
Some conditions in the source code determine that the first thread entry cannot generate thread B entry will generate the most important thing is to debug it yourself to see the general process
Welcome to study and exchange, please point out the shortcomings, if you like it, please like + bookmark, thank you guys