我之见--java多线程 线程安全集合类
2014-08-25 00:26
148 查看
java本身对多线程的支持是很充分的,但在jdk1.5之前集合对多线程的操作几乎都是不安全的,但是集合又是我们经常用到的,如果用不好经常会出问题,下面我们来解析一下:就拿我们最简单的Vector类来说,我们先来看一下使用它的常规用法:
因此代码这样改成这样:
此时的代码确实是线程安全的,没有任何问题,如果我们现在想添加向集合里面添加元素,因此代码可以这样写:
但是到了jdk 5.0之后java提供了很多并发容器来改进同步容器的性能。比如:ConcurrentHashMap 和CopyOnWriteArrayList; 同时还新增了两种容器的类型:
Queue和BlockingQueue. BlockingQueue是一种支持阻塞式添加和获取元素的方式,因此我们可以很简单的实现生产者和消费者模式。
针对上面的ConcurrentModificationException异常我们可以CopyOnWriteArrayList集合可以很快搞定,这是一种写时才复制的容器,当我们在写的时候,发现有别的线程在读,我们先创建新的“副本”,从而可以实现可变性,不过如果我们每次在改变的时候都进行复现,这需要很大的开销。因此这种集合只能针对读操作比较对,写操作比较少的情况,似乎于观察者模式。
ConcurrentHashMap 改变了以往我们在每个操作上面都加锁的情况,采用新的加锁方式,我们可以叫做分段锁,这是一种基于散列的锁,任何读写操作都可以并发访问map,并且一定数量的写入线程可以并发执行。后面文章我们会一起学习。
private static void removeObject(Vector<String> vector,int index) { vector.remove(index); }这样的使用在多线程的情况下感觉会出现,index可能会超出vector容量的大小,可能你会说我们可以在使用之前先检测。
因此代码这样改成这样:
private void removeObject(Vector<String> vector,int index) { if(vector.size()<index) { return; } vector.remove(index); }确实可能是这样避免刚才出现的问题,如果我们还要用另外的一个方法,删除vector最后一个元素,因此我们添加了下面方法:
private void removeLast(Vector<String> vector) { int index = vector.size() - 1; vector.remove(index); }这样也是似乎也是没有问题了,如果两个线程是顺序执行的话,但实际情况我们可能并不能保证线程的顺序执行。因为我们想到了加锁来保证线程的安全,因此上面的方法就变成了,下面的代码:
private void removeObject(Vector<String> vector,int index) { synchronized (vector) { if(vector.size()<index) { return; } vector.remove(index); } } private void removeLast(Vector<String> vector) { synchronized (vector) { int index = vector.size() - 1; vector.remove(index); }
此时的代码确实是线程安全的,没有任何问题,如果我们现在想添加向集合里面添加元素,因此代码可以这样写:
private void addObject(Vector<String> vector, String e) { vector.add(e); }当我们很高兴的时候,却出现了另外一个错误;ConcurrentModificationException,因此我们又不得不对上面的代码进行加锁,几乎我们对集合的任何操作都需要加锁,每个操作都加锁资源消耗是非常大的,而且特别是当我们对集合进行遍历操作的时候,如果其他线程因为加锁的原因必须等待,这样是很不好的。
但是到了jdk 5.0之后java提供了很多并发容器来改进同步容器的性能。比如:ConcurrentHashMap 和CopyOnWriteArrayList; 同时还新增了两种容器的类型:
Queue和BlockingQueue. BlockingQueue是一种支持阻塞式添加和获取元素的方式,因此我们可以很简单的实现生产者和消费者模式。
针对上面的ConcurrentModificationException异常我们可以CopyOnWriteArrayList集合可以很快搞定,这是一种写时才复制的容器,当我们在写的时候,发现有别的线程在读,我们先创建新的“副本”,从而可以实现可变性,不过如果我们每次在改变的时候都进行复现,这需要很大的开销。因此这种集合只能针对读操作比较对,写操作比较少的情况,似乎于观察者模式。
ConcurrentHashMap 改变了以往我们在每个操作上面都加锁的情况,采用新的加锁方式,我们可以叫做分段锁,这是一种基于散列的锁,任何读写操作都可以并发访问map,并且一定数量的写入线程可以并发执行。后面文章我们会一起学习。
相关文章推荐
- 黑马程序员--Java学习笔记之多线程(自定义线程的两种方式对比、线程状态、线程安全)
- Java ,单实例 多线程 ,web容器,servlet与struts1-2.x系列,线程安全的解决方案
- Java多线程与线程安全
- JAVA多线程(一)线程安全问题产生的原因
- java进程、线程、多线程以及线程安全问题
- [Java 多线程] 并发集合类
- 【Java系列】(四)Java多线程---线程安全
- 【Java多线程】之八:单例模式的线程安全
- Java的多线程编程模型2--怎样才线程安全
- Java线程和多线程(五)——单例类中的线程安全
- java多线程基础知识:如何编写线程安全代码
- Java多线程之~~~线程安全容器的非阻塞容器
- Java学习笔记总结篇之集合类和多线程
- java并发实战第六章(2)非阻塞式线程安全列表与一般List集合多线程情况下的比较
- 【Java之Servlet(二)】servlet是单例多线程,以及多线程下如何保证线程安全
- Java ,单实例 多线程 ,web容器,servlet与struts1-2.x系列,线程安全的解决
- java笔记-多线程-线程安全
- java多线程㈡—线程安全问题(同步代码块or同步函数)
- java多线程回顾3:线程安全
- JAVA多线程(二)构建线程安全的类