De poder leer la palabra Intercambiador a entenderla

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

Supongo que te gusta

Origin blog.csdn.net/m0_67601895/article/details/129039160
Recomendado
Clasificación