From being able to read the word Exchanger to understanding it

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

Guess you like

Origin blog.csdn.net/m0_67601895/article/details/129039160