传统的集合我导致线程不安全问题,于是我们应该使用线程安全的集合。
1、使用ConcurrentHashMap代替HashMap,ConcurrentHashMap内部进一步细分了若干个小的HashMap段,默认为16个。
2、ConcurrentSkipListMap:跳表的实现。是一个Map,使用跳表的数据结构进行快速查找,特点:有序的,平衡树,分层的列表、跳跃式查询、空间换时间。
3、使用Vector代替ArrayList。
4、CopyOnWriteArrayList:在读多写少的场合,这个List的性能非常好,远好于Vector。读的时候不加锁,写的时候加锁,并且会拷贝原来的数组,生成一个新的数组,然后对这个拷贝的数组进行写入,然后再把修改过的数组替换原数组,这样,再写入的同时,如果有读的操作,也不会出现冲突问题,因为原数组没有改变。
5、ConcurrentLinkedQueue:高效的并发队列(高并发环境中性能最好的队列),使用链表实现,线程安全的LinkdeList(底层使用CAS无锁机制实现),ConcurrentLinkedQueue(非阻塞式无界队列)容易出问题,入列不等待,出列不等待,可能会造成数据丢失。
6、BlockingQueue接口(阻塞式)使用多,仅仅用来存放runnable接口
工作方式
入列
当插入数据时,超过了队列的总数,会等待(阻塞)
出列
当获取数据时,值为空,会等待(阻塞)
种类
SynchronousQueue直接提交队列
没有容量的情况下,每一个插入操作都要等待响应的删除操作,反之,每一个删除操作都要等待对应的插入操作。不会保存任务,直接交给线程执行,没有空闲线程尝试创建新线程,线程数量达到最大值,则执行拒绝策略。因此通常设置很大的maximumPoolSize值,不然很容易执行拒绝策略
ArrayBlockingQueue有界任务队列
创建时给定容量,新任务进来若大于核心线程数,在不大于最大线程数的前提下,会继续创建,如果大于最大线程数,则执行拒绝策略
写入
offer()当队列满了立即返回false
put()当队列满了会一直等待,直到队列中有空闲的位置
读出
poll()队列为空直接返回null
take()会等待,直到队列内有元素
LinkedBlockingQueue无界任务队列
除非系统资源耗尽,否则不会造成任务入队失败
锁分离,take()和put()操作使用不同的锁,削弱了锁竞争的可能性。实现了取数据和写数据的分离,是两者在真正意义上成为可并发的操作
ProorityBlockingQueue优先任务队列
带有优先级的队列,控制任务的执行先后顺序,特殊的无界队列。
7、Collections工具类可以帮助我们将任意集合包装成安全的集合,一般在并发级别不高的情况下够用,因为上了锁,导致所有对集合的操作全部进入等待状态
Collections.synchronizedMap(new HashMap());
Collections.synchronizedList(new LinkedList<String>());
……有关Collections工具类的不一一列举了。