范例:观察一下类集的问题
import java.util.ArrayList; import java.util.List; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 List<String> all = new ArrayList<String>() ; for (int x = 0; x < 20; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 30; y++) { all.add(Thread.currentThread().getName() + " - " + temp + " - " + y) ; System.out.println(all); } }).start(); ; } } }
该异常主要指的是当你保存的容量个数和你的实际操作数可能不匹配的时候就会出现此异常。
【 并发集合工具类 】
➣ 为了更好的实现集合的高兵法访问处理,创建了一组心的集合工具类。
➣ List和Set集合:
➣ CopyOnWriteArrayList相当于线程安全的ArrayList,实现了List接口。
CopyOnWriteArrayList是支持高并发的;
➣ CopyOnWriteArraySet相当于线程安全的HashSet,它继承了AbstractSet类,
CopyOnWriteArraySet内部包含一个CopyOnWriteArrayList对象,
它是通过CopyOnWriteArrayList实现的。
➣ Map集合:
➣ ConcurrentHashMap是线程安全的哈希表(相当于线程安全的HashMap);
它继承于AbstractMap类,并且实现ConcurrentMap接口。
ConcurrentHashMap是通过“锁分段”来实现的,它支持并发;
➣ ConcurrentSkipListMap是线程安全的有序的哈希表(相当于线程安全的TreeMap);
它继承于AbstactMap类,并且实现ConcurrentNavigableMap接口。
ConcurrentSkipListMap是通过“跳表”来实现的,它支持并发;
➣ ConcurrentSkipListSet是线程安全的有序的集合(相当于线程安全的TreeSet);
它继承于AbstractSet,并实现了NavigableSet接口。
ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的,它也支持并发;
➣ Queue队列:
➣ ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列;
➣ LinkedBlockingQueue是单向链表实现的(指定大小)阻塞队列,该队列按FIFO(先进先出)排序元素;
➣ LinkedBlockingDeque是双向链表实现的(指定大小)双向并发阻塞队列,
该阻塞队列同时支持FIFO和FILO两种操作方式;
➣ ConcurrentLinkedQueue是单向链表实现的无界队列,该队列按FIFO(先进先出)排序元素。
➣ ConcurrentLinkedDeque是双向链表实现的无界队列,该队列同时支持FIFO和FILO两种操作方式。
【 并发单值集合类 】
juc包里面提供有CopyOnWriteArrayList、CopyOnWriteArraySet很明显是针对于List与Set接口实现的子类。
范例:使用CopyOnWriteArrayList实现多线程异步访问
import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 List<String> all = new CopyOnWriteArrayList<String>() ; for (int x = 0; x < 2; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 10; y++) { all.add(Thread.currentThread().getName() + " - " + temp + " - " + y) ; System.out.println(all); } }).start(); ; } } }
范例:使用CopyOnWriteArraySet实现多线程异步访问
import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 Set<String> all = new CopyOnWriteArraySet<String>() ; for (int x = 0; x < 2; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 10; y++) { all.add(Thread.currentThread().getName() + " - " + temp + " - " + y) ; System.out.println(all); } }).start(); ; } } }
以后如果某一个类需要存储用户的公共资源信息,且多个线程允许同时写入数据的话,就可以考虑使用此类集合实现处理。
【 ConcurrentHashMap子类 】
Map的子类,以下是它的继承构造:
-------------------------
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>,Serializable
-------------------------
Public interface ConcurrentMap<K,V> extends Map<K,V>范例:默认情况下ConcurrentHashMap的基本使用
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 Map<String, String> all = new ConcurrentHashMap<String,String>() ; for (int x = 0; x < 20; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 10; y++) { all.put(Thread.currentThread().getName(), "x = " + temp + "、y = " + y); System.out.println(all); } }).start(); ; } } }使用ConcurrentHashMap并不仅仅是去解决。
”java.util.ConcurrentModificationException”异常,Map集合的主要特征是做数据的查询处理操作,所以在ConcurrentHashMap设计的时候考虑到了数据更新的安全性与数据查询的并发性。
ConcurrentHashMap的整体特征:写的时候同步写入,使用独占锁,读的时候为了保证性能使用了共享锁。
【跳表(Skip)集合】
跳表集合本质上的功能是一种快速查询功能,也就是说它会在一个有序的链表里面选择一些数据作为检索的种子数。
用这些种子数方便进行数据的查找,非常类似于二分法。
在juc的开发包里面提供有跳表的多线程支持操作类:ConcurrentSkipListMap、ConcurrentSkipListSet。
范例:观察调表实现
import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 Map<String, String> all = new ConcurrentSkipListMap<String,String>() ; for (int x = 0; x < 20; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 10; y++) { all.put(Thread.currentThread().getName(), "x = " + temp + "、y = " + y); } }).start(); ; } System.out.println(all.get("Thread-0")); } } 输出结果:x = 0、y = 9
范例:使用“ConcurrentSkipListSet”子类
import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; public class MLDNTestDemo { public static void main(String[] args) throws Exception { // 异步处理 Set<String> all = new ConcurrentSkipListSet<String>() ; for (int x = 0; x < 2; x++) { int temp = x ; new Thread(()->{ for (int y = 0; y < 10; y++) { all.add(Thread.currentThread().getName() + " - " + temp + " - " + y) ; } }).start(); } System.out.println(all.contains("Thread-0 - 0 - 0")); } }如果要想保证快速的定位查询,那么使用调表是最快的,因为其检索的算法要比顺序检索强许多。