标签:上下文 占用 https 无效 设计 this 升级 lan 方式
当一个线程到达栅栏时,会检查是否有其他线程已经到达栅栏.
若没有,则该线程进入等待.
若有,则与等待的其他线程交换各自的数据,然后继续执行.
Participant
继承自ThreadLocal
,用来保存线程本地变量Node
.Node
存储用于单槽交换和多槽交换的字段.流程:
slot
字段指向自身的Node
节点,表示槽位已被占用.slot
已被占用.则后续的线程将槽位slot
清空,取出Node
中的item
作为交换的数据.Node
中的match
字段中,并唤醒先到达的线程.match
是否为空.不为空则退出自旋,将match
中的数据返回.触发机制:
在单槽位交换中,若:多个匹配线程竞争修改slot
槽位,导致线程CAS修改slot
失败,则初始化arena
多槽位数组,后续的交换使用多槽位交换.
流程:
spin->yield->block
的锁升级方式进行优化的等待其他线程到达.若有线程到达,则交换数据后返回交换后的数据.注:
数组是连续的内存地址空间.多个slot会被加载到同一个缓存行上.
当一个slot
改变时,导致该slot
所在的缓存行上所有的数据都无效,需要重新从内存加载.
slot
,增加并发执行的吞吐量.示例:
public class ProducerAndConsumer {
@Test
public void test() throws InterruptedException {
Exchanger<Integer> exchanger = new Exchanger<>();
new Thread(new Producer(exchanger)).start();
new Thread(new Consumer(exchanger)).start();
TimeUnit.SECONDS.sleep(20);
}
}
class Producer implements Runnable {
private int[] array = new int[5];
private final Exchanger exchanger;
public Producer(Exchanger exchanger){
this.exchanger = exchanger;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
TimeUnit.SECONDS.sleep(2);
array[i] = i;
System.out.println("生产者生产的数据为: " + array[i]);
int exchange = (int) exchanger.exchange(array[i]);
System.out.println("生产者交换后的数据为: "+exchange);
System.out.println("生产者的对应的数据是否改变: " + array[i]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private int[] array = new int[5];
private final Exchanger exchanger;
public Consumer(Exchanger exchanger){
this.exchanger = exchanger;
}
@Override
public void run() {
int index = 0;
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("消费者交换前的数据为: " + array[index]);
int exchange = (int) exchanger.exchange(array[index]);
index++;
System.out.println("消费者获得的数据为: " + exchange);
System.out.println("消费者交换后的数据: " + array[index]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
注:
参考:
标签:上下文 占用 https 无效 设计 this 升级 lan 方式
原文地址:https://www.cnblogs.com/truestoriesavici01/p/13216205.html