Java并发编程(三):并发容器类和辅助类
并发容器类和辅助类
Java提供了很多支持并发的容器类,例如我们比较熟悉的用来在并发场景下代替HashMap
的ConcurrentHashMap
类:
- JDK1.8之前 采用“锁分段机制”
- JDK1.8之后 采用 synchronized 锁住Node节点,结合CAS和volatile实现
除此之外,还有:
ConcurrentSkipListMap
通常优于同步的TreeMap
- 在应对并发场景下多次读取和遍历操作时的
ArrayList
代替者CopyOnWriteArrayList
等等
并发容器类的使用
来看下面一段代码
public class TestCopyOnWriteArraySet {
public static void main(String[] args)
{
HelloThread ht = new HelloThread();
for (int i=0;i<10;i++)
{
new Thread(ht).start();
}
}
}
class HelloThread implements Runnable{
private static List<String> list = Collections.synchronizedList(new ArrayList<>());
static {
list.add("A");
list.add("B");
list.add("C");
}
@Override
public void run() {
Iterator<String> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
list.add("A");
}
}
}
代码逻辑:
HelloThread
线程中有个list
,初始数据为 A B Crun
方法里打印下一个对象并添加新对象- 还是在主方法里用十个线程同时进行上述操作
实际上执行结果:
抛出ConcurrentModificationException
异常
发生了什么?
发生了并发修改异常,迭代操作同一个数据源
怎么解决?
使用Java提供的 CopyOnWriteArrayList
容器类即可
把之前的 ArrayList
替换为 CopyOnWriteArrayList
// private static List<String> list = Collections.synchronizedList(new ArrayList<>());
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
程序可以正常执行
CopyOnWriteArrayList
每次写入时,都会在底层复制新列表,然后再添加,避免了并发修改异常
所以比较适合迭代多的场景,不适合添加操作过多的场景
CountDownLatch
闭锁
是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
- 目标:只有当其他所有线程的运算全部完成,当前运算才继续执行
可以使用闭锁这个性质,来计算所有线程运行完毕究竟耗费了多少时间
即把主线程执行的逻辑放到所有线程执行完毕后再执行
看下面的实现代码:
import java.util.concurrent.CountDownLatch;
public class TestCountDownLatch {
public static void main(String[] args) throws InterruptedException {
//初始值为5,每次有线程完成就递减1,直到0才可以继续执行
CountDownLatch latch = new CountDownLatch(5);
LatchDemo latchDemo =new LatchDemo(latch);
//10个线程没启动时的时间
long start = System.currentTimeMillis();
for (int i=0;i<10;i++)
{
new Thread(latchDemo).start();
}
//等待latch闭锁
latch.await();
//闭锁中count减到0了,记录现在的时间
long end = System.currentTimeMillis();
System.out.println("耗费时间:"+(end-start));
}
}
class LatchDemo implements Runnable{
private CountDownLatch latch;
//构造函数
public LatchDemo(CountDownLatch latch)
{
this.latch = latch;
}
@Override
public void run() {
//避免冲突
synchronized (this)
{
try{
//打印1-50000之间的偶数
for(int i = 0;i<50000;i++)
{
if(i%2==0)
{
System.out.println(i);
}
}
}
//无论如何,此方法最后都把闭锁的count减一
finally {
latch.countDown();
}
}
}
}
实际执行结果:
这时候算出的时间就是等待所有线程运行完之后花费的时间
还没有评论,来说两句吧...