La gran anatomía de Exchanger:
Esta cosa es un hilo de intercambio de datos que intercambia datos en este intercambio como se muestra en la figura
Los datos del hilo 1 esperan la llegada de los datos del hilo 2 en el switch (Intercambiador) para el intercambio de datos
La condición del intercambio es que haya varios pares de subprocesos que se puedan intercambiar al mismo tiempo.
demostración de código
Preparar hilo 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交换完成继续干活");
}
}
Preparar el hilo 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数据交换完成进行接下来的工作");
}
}
prueba de inicio
public class ExchangerCS {
public static void main(String[] args) {
Exchanger<String> stringExchanger = new Exchanger<>();
new ExchangerA(stringExchanger).start();
new ExchangerB(stringExchanger).start();
}
}
Análisis de código fuente del método central en Exchanger
Cuando creamos un nuevo Intercambiador, declararemos el tipo en el tipo genérico, y este tipo genérico no puede intercambiar datos entre Intercambiadores. Le damos un tipo genérico al Intercambiador, y luego usa el nodo nodo para recibir e intercambiar nuestros tipos de manera uniforme. intercambio de nodos .node
La posición del elemento es donde se colocan los datos del hilo A
coincidencia es la ubicación de datos que se intercambiará con un hilo en el futuro
Estacionado es el primer hilo para esperar aquí
El método central de Exchanger
intercambiador.intercambio
El significado general es que cuando el primer subproceso trae datos, primero juzgará si se trata de un intercambio de una sola ranura o de varias ranuras.
Use slotExchange para una sola ranura
Intercambio de arena para caminar con varias ranuras
Tome el método de ranura única aquí
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;
}
diagrama sencillo
Es mejor mirar el código fuente paso a paso y hacer clic para ver si es más útil.
P: Los datos del nodo traídos por el hilo al Intercambiador
ranura: nodo de ranura única (generalmente el valor del primer subproceso que ingresa al Intercambiador es nulo)
q: q es similar a slot, reemplazará slot y asignará nulo a slot
item: guardar los datos traídos por el hilo
Coincidencia: guardar los datos intercambiados
estacionado: guardar el hilo actual
Algunas condiciones en el código fuente determinan que la entrada del primer subproceso no puede generar la entrada del subproceso B generará lo más importante es depurarlo usted mismo para ver el proceso general
Bienvenido a estudiar e intercambiar, señale las deficiencias, si le gusta, haga clic en Me gusta + marcador, gracias chicos