java多线程(七) 之 同步容器类
来源:互联网 发布:java 线程休眠 编辑:程序博客网 时间:2024/05/21 21:35
同步容器类都是线程安全的,但在某些情况下可能需要额外的客户端加锁来保护复合操作,比如如下:
1.线程不安全的复合操作1:
import java.util.Vector;public class UnsafeVectorOperation { public static Object getLast(Vector<?> list){ int lastIndex = list.size() - 1; return list.get(lastIndex); } public static void deleteLast(Vector<?> list){ int lastIndex = list.size() -1; list.remove(lastIndex); }}
线程B可能获取了list.size()-1的值之后,此时如果线程A执行了list.remove(lastIndex),那么线程B再接着执行return list.get(lastIndex);将会报ArrayIndexOutOfBoundsException异常
2.线程不安全的复合操作2:
如果给方法加上synchronized锁呢?
import java.util.Vector;public class UnsafeVectorOperation2 { public synchronized static Object getLast(Vector<?> list){ int lastIndex = list.size() - 1; return list.get(lastIndex); } public synchronized static void deleteLast(Vector<?> list){ int lastIndex = list.size() -1; list.remove(lastIndex); }}
结论是,线程仍然不安全,理由:
虽然按照上一题的中的线程A,B之间是安全的,但是,如果是下面的情况:
Vector list;
A线程:UnsafeVectorOperation2.getLast(list)
C线程:list.remove(list.size()-1);
所以上面的代码只能限制线程同时调用UnsafeVectorOperation2里的方法安全,一旦有其他线程也调用list,那么上面的代码就傻逼了.
3.如果给list上锁,使得复合操纵变为原子操作.
import java.util.Vector;public class UnsafeVectorOperation3 { public static Object getLast(Vector<?> list){ synchronized (list) { int lastIndex = list.size() - 1; return list.get(lastIndex); } } public static void deleteLast(Vector<?> list){ synchronized(list){ int lastIndex = list.size() -1; list.remove(lastIndex); } }}
UnsafeVectorOperation3 当中的确不存在线程不安全的问题了,但是其他线程对list的操作仍然线程不安全,这个不安全可以来自其他线程对UnsafeVectorOperation3的调用,例如:
Vector list;线程B调用:deleteLast(list)线程C执行: for(int i =0;i<list.size();i++) list.get(i);/****************************/假设size为10,C的i已经遍历到了9如果B,C线程执行的情况是:C: 执行i<list.size() //i=9<size=10,继续遍历B: 执行了deleteLast(list) //size将变为9C: 执行list.get(i) //报ArrayIndexOutOfBoundsException异常
4.带有客户端锁的迭代,这下安全了,只不过…
synchronized(list){ for(int i =0;i<list.size();i++) list.get(i);}
在遍历期间,将会导致其他线程对list的访问,数据量越大,迭代越长,并发效率大大降低.很多时候得不偿失.
5.使用迭代器来迭代,解决并发效率低的问题:
至今所有的容器都并没有真正达到”既百分百安全,效率又很高”,而只能采取折中的方案.
for(Object o:list){}
迭代器是一种权衡利弊的考虑,采取的是”及时失败”的策略,一旦迭代的数据被修改掉,就会抛出一个ConcurrentModificationException异常
开发的时候,可能需要根据不同的实际情况,选择合适的方案,3,4,5的程序例子都是可以使用的.
6.隐藏迭代器:
有时候,你可能会犯下面的错误:
目的:设计一个百分之百安全的类,代码如下:
import java.util.HashSet;import java.util.Random;import java.util.Set;public class HiddenIterator { private final Set<Integer> set = new HashSet<Integer>(); public synchronized void add(Integer i){ set.add(i); } public synchronized void remove(Integer i){ set.remove(i); } public void addTenRandomNum(){ Random r = new Random(); for(int i = 0;i<10;i++){ add(r.nextInt()); } //容易犯错误的地方,set.toString()在set集合里会进行迭代操作,而并没有上锁 //在集合的操作里面,有些容易让人忘记的迭代操作: toString,containsAll,removeAll,retainAll //这些间接迭代的操作都有可能抛出ConcurrentModificationException异常 System.out.println("DEBUG: added ten elements to "+set.toString()); }}
- java多线程(七) 之 同步容器类
- Java多线程之同步类容器与并发容器
- (七) Java多线程详解之常用线程同步工具类
- Java多线程之同步容器与并发容器
- java 多线程 同步类容器与并发类容器
- java多线程(9)--同步类容器和并发类容器
- Java多线程之同步
- java多线程之-同步
- Java多线程之同步辅助类(1)
- Java多线程之同步工具类
- java多线程(九) 之 同步工具类
- Java多线程之七锁
- (七)java多线程之Condition
- 高并发基础之同步容器(七)
- 多线程系列提高(4)--同步容器类
- Java5 多线程(七)--Exchanger同步工具类
- Java多线程之同步关键字
- Java多线程之线程同步
- eclipse远程服务器上dubug
- Nexus仓库和仓库组
- spring中的定时@Scheduled页脚
- Java volatile关键字详解
- JAVA内存结构之运行时栈帧结构
- java多线程(七) 之 同步容器类
- activity的启动模式有哪些?是什么含义?(三)
- Trie图
- lvm学习日记
- 微信的野心到底有多可怕
- 对于Packet for query is too large(mysql写入数据过大) 问题的处理方法二
- UVA
- UOJ #34 多项式乘法
- FileProvider文件共享