#yyds干货盘点# Exchanger详解

Posted 灰太狼_cxh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点# Exchanger详解相关的知识,希望对你有一定的参考价值。

Exchanger详解

Exchanger简介

Exchanger用于进行两个线程之间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange()方法交换数据,当一个线程先执行exchange()方法后,它会一直等待第二个线程也执行exchange()方法,当这两个线程到达同步点时,这两个线程就可以交换数据了。

Exchanger实现机制

for (;;) 
if (slot is empty) // offer
// slot为空时,将item 设置到Node 中
place item in a Node;
if (can CAS slot from empty to node)
// 当将node通过CAS交换到slot中时,挂起线程等待被唤醒
wait for release;
// 被唤醒后返回node中匹配到的item
return matching item in node;

else if (can CAS slot from node to empty) // release
// 将slot设置为空
// 获取node中的item,将需要交换的数据设置到匹配的item
get the item in node;
set matching item in node;
// 唤醒等待的线程
release waiting thread;

// else retry on CAS failure

比如有2条线程A和B,A线程交换数据时,发现slot为空,则将需要交换的数据放在slot中等待其它线程进来交换数据,等线程B进来,读取A设置的数据,然后设置线程B需要交换的数据,然后唤醒A线程,原理就是这么简单。但是当多个线程之间进行交换数据时就会出现问题,所以Exchanger加入了slot数组。

Exchanger源码解析

内部类 - Participant

static final class Participant extends ThreadLocal<Node> 
public Node initialValue() return new Node();

Participant的作用是为每个线程保留唯一的一个Node节点, 它继承ThreadLocal,说明每个线程具有不同的状态。

内部类 - Node

@sun.misc.Contended static final class Node 
// arena的下标,多个槽位的时候利用
int index;
// 上一次记录的Exchanger.bound
int bound;
// 在当前bound下CAS失败的次数;
int collides;
// 用于自旋;
int hash;
// 这个线程的当前项,也就是需要交换的数据;
Object item;
//做releasing操作的线程传递的项;
volatile Object match;
//挂起时设置线程值,其他情况下为null;
volatile Thread parked;

在Node定义中有两个变量值得思考:bound以及collides。前面提到了数组area是为了避免竞争而产生的,如果系统不存在竞争问题,那么完全没有必要开辟一个高效的arena来徒增系统的复杂性。首先通过单个slot的exchanger来交换数据,当探测到竞争时将安排不同的位置的slot来保存线程Node,并且可以确保没有slot会在同一个缓存行上。如何来判断会有竞争呢? CAS替换slot失败,如果失败,则通过记录冲突次数来扩展arena的尺寸,我们在记录冲突的过程中会跟踪“bound”的值,以及会重新计算冲突次数在bound的值被改变时。

以上是关于#yyds干货盘点# Exchanger详解的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# Phaser详解

#yyds干货盘点# Semaphore详解

#yyds干货盘点# JUC锁: ReentrantReadWriteLock详解

#yyds干货盘点#Golang make和new的区别详解

#yyds干货盘点# JUC锁: ReentrantLock详解

#yyds干货盘点# CountDownLatch详解