博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JUC——并发集合类
阅读量:5883 次
发布时间:2019-06-19

本文共 7882 字,大约阅读时间需要 26 分钟。

如果要进行多个数据的保存,无疑首选类集(List、Set、Queue、Map),在类集的学习的时候也知道一个概念:许多集合的子类都具有同步与异步的差别,但是如果真的要在多线程之中去使用这些类,是否真的可以用呢?

范例:观察一下类集的问题:

package so.strong.mall.concurrent;import java.util.ArrayList;import java.util.List;public class ListDemo {    public static void main(String[] args) {        final List
all = new ArrayList<>(); for (int i = 0; i < 20; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 20; j++) { all.add(Thread.currentThread().getName() + "-" + temp + "-" + j); System.out.println(all); } } }).start(); } }}

不过很遗憾的是这个时候以上的代码出现了“java.util.ConcurrentModificationException”,该异常主要指的是当保存的容量个数和实际操作数可能不匹配的时候就出现该异常。

 

并发集合类

为了更好的实现集合的高并发访问处理,juc中创建一组新的集合工具类:

List和Set集合

public class CopyOnWriteArrayList
implements List
, RandomAccess, Cloneable, java.io.Serializable

  CopyOnWriteArrayList相当于线程安全的ArrayList,它实现了List接口。CopyOnWriteArrayList是支持高并发的。

public class CopyOnWriteArraySet
extends AbstractSet
implements java.io.Serializable

  相当于线程安全的HashSet,它继承与AbstractSet类。

  CopyOnWriteArraySet内部包含一个CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList来实现的。

Map集合

public class ConcurrentHashMap
extends AbstractMap
implements ConcurrentMap
, Serializable 

  ConcurrentHashMap是线程安全的哈希表,相当于线程安全的HashMap,它继承与AbstractMap类,并且实现了ConcurrentMap接口。ConcurrentHashMap是通过“锁分段”来实现的,它支持并发;

public class ConcurrentSkipListMap
extends AbstractMap
implements ConcurrentNavigableMap
,Cloneable,java.io.Serializable

  ConcurrentSkipListMap是线程安全的有序哈希表(相当于线程安全的TreeMap),它继承于AbstractMap类,并且实现了ConcurrentNavigableMap接口。ConcurrentSkipListMap是通过“跳表”来实现的,它支持并发;

public class ConcurrentSkipListSet
extends AbstractSet
implements NavigableSet
, Cloneable, java.io.Serializable

  ConcurrentSkipListSet是线程安全的有序的集合(相当于线程安全的TreeSet);它继承了AbstractSet,并且实现了NavigableSet接口。ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的,它也支持并发。

Queue队列

public class ArrayBlockingQueue
extends AbstractQueue
implements BlockingQueue
, java.io.Serializable

  ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列;

public class LinkedBlockingQueue
extends AbstractQueue
implements BlockingQueue
, java.io.Serializable

  LinkedBlockingQueue是单向链表实现的(指定大小)阻塞队列,该队里按FIFO先进先出排序元素;

public class LinkedBlockingDeque
extends AbstractQueue
implements BlockingDeque
, java.io.Serializable

  LinkedBlockingDeque是双向链表实现的(指定大小)双向并发阻塞队列,该阻塞队列同时支持FIFO和FILO两种操作方式;

public class ConcurrentLinkedQueue
extends AbstractQueue
implements Queue
, java.io.Serializable

  ConcurrentLinkedQueue是单向链表实现的无界队列,该队列按FIFO排序元素;

public class ConcurrentLinkedDeque
extends AbstractCollection
implements Deque
, java.io.Serializable

  ConcurrentLinkedDeque是双向链表的无界队列,该阻塞队列同时支持FIFO和FILO两种操作方式。

单值并发集合

juc包里面提供的CopyOnWriteArrayList、CopyOnWriteArraySet很明显是针对于List和Set接口实现的子类。

范例:使用CopyOnWriteArrayList实现多线程访问

package so.strong.mall.concurrent;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;public class ListDemo {    public static void main(String[] args) {        final List
all = new CopyOnWriteArrayList<>(); for (int i = 0; i < 20; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 20; j++) { all.add(Thread.currentThread().getName() + "-" + temp + "-" + j); System.out.println(all); } } }).start(); } }}

 范例:使用CopyOnWriteArraySet实现多线程访问

package so.strong.mall.concurrent;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;public class ListDemo {    public static void main(String[] args) {        final Set
all = new CopyOnWriteArraySet<>(); for (int i = 0; i < 20; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 20; j++) { all.add(Thread.currentThread().getName() + "-" + temp + "-" + j); System.out.println(all); } } }).start(); } }}

如果某一个类需要存储用户的公共资源,并且多个线程允许同时写入数据的话,就可以考虑使用此类集合实现处理。

 

ConcurrentHashMap

观察继承结构:

public class ConcurrentHashMap
extends AbstractMap
implements ConcurrentMap
, Serializable

发现它是ConcurrentMap接口的子类,而ConcurrentMap接口定义如下:

public interface ConcurrentMap
extends Map

范例:默认情况下使用ConcurrentHashMap的基本使用:

package so.strong.mall.concurrent;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapDemo {    public static void main(String[] args) {        final Map
all = new ConcurrentHashMap<>(); for (int i = 0; i < 2; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 3; j++) { all.put(Thread.currentThread().getName(), "x = " + temp + ",j = " + j); System.out.println(all); } } }).start(); } }}

  使用ConcurrentHashMap并不仅仅是去解决“java.util.ConcurrentModificationException”异常,Map集合的主要特征是做数据的查询操作,所以在ConcurrentHashMap设计的时候考虑到了数据更新的安全性和数据查询的并发性。

ConcurrentHashMap的整体特征:写的时候同步写入,使用独占锁,读的时候为了保证性能使用了共享锁。

 

跳表(Skip)集合

跳表集合本质上的功能是一种快速查询功能,也就是说它会在一个有序的链表里面选择一些数据作为检索的种子数,那么利用这些种子数方便进行数据的查找,非常类似于二分法。

在juc开发包里面提供有跳表的多线程支持程序类:ConcurrentSkipListMap、ConcurrentSkipListSet。

范例:观察跳表实现ConcurrentSkipListMap

package so.strong.mall.concurrent;import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;import sun.java2d.pipe.SpanIterator;import java.util.Map;import java.util.concurrent.ConcurrentSkipListMap;public class SkipDemo {    public static void main(String[] args) {        final Map
all = new ConcurrentSkipListMap<>(); for (int i = 0; i < 20; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 30; j++) { all.put(Thread.currentThread().getName(), "x=" + temp + ",j=" + j); } } }).start(); } System.out.println(all.get("Thread-0")); }}

范例:使用ConcurrentSkipListSet

package so.strong.concurrents;import java.util.Set;import java.util.concurrent.ConcurrentSkipListSet;public class SkipDemo {    public static void main(String[] args) {        final Set
all = new ConcurrentSkipListSet<>(); for (int i = 0; i < 2; i++) { final int temp = i; new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { all.add(Thread.currentThread().getName()+"-"+temp+"-"+j); } } }).start(); } System.out.println(all.contains("Thread-0-0-1")); }}

如果要想保证快速地定位查询,那么使用跳表是最快速的,因为其检索的算法要比顺序检索强许多。

 

转载于:https://www.cnblogs.com/itermis/p/9066144.html

你可能感兴趣的文章
通过Typings为Visual Studio Code增强智能提示功能
查看>>
5天不再惧怕多线程——第二天 锁机制
查看>>
互联网推送服务原理:长连接+心跳机制(MQTT协议)
查看>>
Android 系统ID介绍
查看>>
Know How And When To Use System.Message_Level To Control Messages In Oracle Forms
查看>>
Atitit 验证 数字验证 非空验证的最佳算法 h5
查看>>
ASP.NET Core 发布
查看>>
cocos2d-x-lua基础系列教程五(lua单例)
查看>>
升级_开阔视野之Oracle图形化升级(dbca建库后升级)—10.2.0.1.0升为10.2.0.5.0
查看>>
深入浅出 - Android系统移植与平台开发(七)- 初识HAL【转】
查看>>
初探linux子系统集之timer子系统(三)
查看>>
利用VisualVM监视远程JVM
查看>>
TortoiseGit学习系列之TortoiseGit基本操作将提交到本地的项目推送到在线仓库(图文详解)...
查看>>
关于spring mybateis 定义resultType="java.util.HashMap"
查看>>
『TensorFlow』读书笔记_Inception_V3_上
查看>>
python爬虫从入门到放弃(四)之 Requests库的基本使用(转)
查看>>
程序员怎么留住健康?
查看>>
【ANT】ant使用
查看>>
Go基础系列:Go接口
查看>>
miniprogrampatch 提供 watch 和 computed 特性
查看>>