博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程(十)使用线程安全的集合
阅读量:4293 次
发布时间:2019-05-27

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

在多线程中,如果要并发的修改一个数据结构,那么很有可能会破坏这个数据结构。例如,一个线程可能要向一个散列表中插入一个元素,假如在调整各个桶之间的链接关系时被剥夺了控制权,而此时正好有另外一个线程正在遍历链表,则可能会产生异常或者死循环。

可以通过锁来保护共享的数据结构,但是选择线程安全的实现作为替代可能更容易一些。

一、旧的线程安全的集合

任何集合类都可以通过使用同步包装器变成线程安全的:

List
synchArrayList = Collections.synchronizedList(new ArrayList
());Map
synchMap = Collections.synchronizedList(new HasMap
());
  • 1
  • 2
  • 3

结果集合的方法使用锁加以保护,提供线程安全的访问。

如果在另一个线程可能进行修改时要对集合进行迭代,任然需要使用封锁。

synchronized(synchHashMap){    Iterator
iter = synchHashMap.keySet().iterator(); while(iter.hasNext()) //遍历}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果使用for each 循环必须使用同样的代码,因为循环使用了迭代器。如果在迭代的过程中另一个线程修改集合,迭代器会失效,抛出ConcurrentModificationException异常,因此并发的修改可以被可靠的检测出来。

二、高效的映像、集合和队列

java.util.concurrent包提供了映像、有序集和队列的高效实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentLinkedQueue。这些集合通过复杂的算法,通过允许并发的访问数据结构的不同部分来使竞争极小化。

这些集合返回弱一致性的迭代器。这意味着迭代器不一定能反映出他们被构造之后的所有的修改,但是,他们不会将同一个值返回两次,也不会抛出ConcurrentModificationException的异常。

例如下面的例子:

import java.util.*;import java.util.concurrent.*;/* *   ConcurrentLinkedQueue是“线程安全”的队列,而LinkedList是非线程安全的。 * *   下面是“多个线程同时操作并且遍历queue”的示例 *   (01) 当queue是ConcurrentLinkedQueue对象时,程序能正常运行。 *   (02) 当queue是LinkedList对象时,程序会产生ConcurrentModificationException异常。 * * @author skywang */public class Main {
// TODO: queue是LinkedList对象时,程序会出错。 //private static Queue
queue = new LinkedList
(); private static Queue
queue = new ConcurrentLinkedQueue
(); public static void main(String[] args) { // 同时启动两个线程对queue进行操作! new MyThread("ta").start(); new MyThread("tb").start(); } private static void printAll() { String value; Iterator iter = queue.iterator(); while(iter.hasNext()) { value = (String)iter.next(); System.out.print(value+", "); } System.out.println(); } private static class MyThread extends Thread {
MyThread(String name) { super(name); } @Override public void run() { int i = 0; while (i++ < 6) { // “线程名” + "-" + "序号" String val = Thread.currentThread().getName()+i; queue.add(val); // 通过“Iterator”遍历queue。 printAll(); } } }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

使用ConcurrentLinkedQueue时不会报错 

这里写图片描述

使用LinkedList时产生错误: 

这里写图片描述

你可能感兴趣的文章
Lucene初探
查看>>
Git简介、安装及创建版本库
查看>>
如何在JavaScript中编写一个简单的Bug跟踪器
查看>>
jQuery 效果 - 滑动
查看>>
对Java多态的深入理解
查看>>
javascript重点-表达式和运算符_优就业
查看>>
springmvc整合poi导出报表
查看>>
Oracle Data Guard延迟的原因
查看>>
java8 遍历数组的几种方式
查看>>
java基础知识(七)--Object类
查看>>
Object.prototype.toString_优就业
查看>>
JS之浏览器对象BOM
查看>>
分布式架构系列: 负载均衡技术详解
查看>>
python3安装scrapy
查看>>
python正则表达式入门一
查看>>
python正则表达式入门二
查看>>
scrapy运行
查看>>
XPATH入门
查看>>
python爬虫 CSS选择器
查看>>
正常关闭java程序
查看>>