并发容器
程序员文章站
2022-07-13 08:58:54
...
exchanher交换数据,代码如下:
package concurrent;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.*;
public class ExchangerDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
executor.execute(new Runnable() {
String data1 = "克拉克森,小拉里南斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "格里芬";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "哈里斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "以赛亚托马斯,弗莱";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.shutdown();
}
private static void nbaTrade(String data1, Exchanger exchanger) {
try {
System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = (String) exchanger.exchange(data1);
System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行得到结果如下,从结果可以看出来,data1和data2得到了交换
pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
pool-1-thread-2在交易截止之前把 格里芬 交易出去
pool-1-thread-3在交易截止之前把 哈里斯 交易出去
pool-1-thread-4在交易截止之前把 以赛亚托马斯,弗莱 交易出去
pool-1-thread-2交易得到哈里斯
pool-1-thread-3交易得到格里芬
pool-1-thread-4交易得到克拉克森,小拉里南斯
pool-1-thread-1交易得到以赛亚托马斯,弗莱
对于增删操作用得上List或者Set。都是针对整个容器,每次操作都不可避免地需要锁住整个容器空间,这样性能大打折扣,实现线程安全的List/Set只要修改操作的时候进行同步,比如java.util.Collections.synchronizedList(List)或者java.util.Collections.synchronizedSet(Set),当然也可以用Lock来实现List/Set。但这种情况下是多读少写,如果能实现更优秀的算法,ReadWriteLock,CopyOnWriteArrayList/CopyOnWriteArraySet都是思路,后两者最大的好处就是"读“不用锁。思路是改的时候复制一份新的List/Set,在新的上修改,然后复制给旧的,写操作要加锁。可以点击下面链接看看源码。
ArrayList和CopyOnWriteArrayList
上面链接可以看出CopyOnWriteArrayList有几个要点
- 实现了List接口
- 内部持有一个ReentrantLock lock = new ReentrantLock();
- 底层是用volatile transient声明的数组 array
- 读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
增删改的时候,都会创建一个新的数组,改的过程中,get可按照原来的数组进行查看。如果在增删改中直接修改原来的数组,可能会造成执行程序读操作获取不到数据。支持读多少写的并发情况。