JAVA中有许多线程安全的基础模块类,一般情况下,这些基础模块类能满足我们需要的所有操作,但更多时候,他们并不能满足我们所有的需要。此时,我们需要想办法在不破坏已有的线程安全类的基础上添加一个新的原子操作。有如下4中方案: 
1 修改类的源码,以添加新的原子操作 
2 继承该线程安全类,并添加原子操作 
3 使用客户端加锁方式 
4 使用组合方式(推荐) 
一般来讲,修改源码的方式不太可行,这样会破坏原有类的封装性而且有些时候,源码不可获得。我们从第二种方式开始举例:

假设现在对于类Vector,我们知道它是线程安全类。如果想为他添加一个“若没有则添加”方法,可是如下进行:

  1. public class ImprovedVector<T> extends Vector<T>{
  2. public synchronized boolean putIfAbsent(T x){
  3. boolean flag=contains(x);
  4. if(!flag)
  5. add(x);
  6. return !flag;
  7. }
  8. }

我们来分析上面的代码:使用ImprovedVector类对象的内置锁,保证了contains()和add()方法的原子性,由于ImprovedVector类对象的内置锁也就是Vector类对象的内置锁(即add()方法和contains()方法的锁),这样有保证了add()方法和contains()方法的可见性,可以达到预期效果。

第三种方法举例:

  1. (错误的实现)
  2. public class ImprovedList<T>{
  3. public List<T> list=Collections.synchronizedList(new ArrayList<T>());
  4. public synchronized boolean putIfAbsent(T x){
  5. boolean flag=list.contains(x);
  6. if(!flag)
  7. list.add(x);
  8. return !flag;
  9. }
  10. }

上面的例子是一个错误的例子,我们来分析下:首先,synchronized保证了list.contains()方法和list.add()方法的原子性,假设现在有一个类对象在执行putIfAbsent()方法,而且即将执行(还没执行)list.add(2)方法,此时,有另外一个线程抢先执行了list.add(2)方法,该线程执行完毕之后,释放了list的锁,接着即将执行(还没执行)list.add(2)方法开始得到CPU并执行。瞧,这个过程中,数字2被添加了2次。就是说,上面的代码中仅仅保证了contains()方法和add()方法的原子性,以及对对list引用操作的互斥性,并没有保证list.add()方法的可见性。 
仔细想想,问题出在putIfAbsent()方法的锁与list对象的锁不是同一个,putIfAbsent()方法的锁是ImprovedList类的锁,而list.add()方法的锁是Collections.synchronizedList()使用的锁,因此将上面的代码改成:

  1. (正确的实现)
  2. public class ImprovedList<T>{
  3. public List<T> list=Collections.synchronizedList(new ArrayList<T>());
  4. public synchronized boolean putIfAbsent(T x){
  5. synchronized(list){
  6. boolean flag=list.contains(x);
  7. if(!flag)
  8. list.add(x);
  9. return !flag;
  10. }
  11. }
  12. }

第四种方法举例:

  1. public class ImprovedList<T> implements List<T>{
  2. private final List<T> list;
  3. public ImprovedList(List<T> list){
  4. this.list=list;
  5. }
  6. public synchronized boolean putIfAbsent(T x){
  7. boolean flag=list.contains(x);
  8. if(!flag)
  9. list.add(x);
  10. return !flag;
  11. }
  12. }
  13. ...实现List<T>接口中的其他方法
  14. }

乍一看发现,上面的代码在安全性方面好像弱了好多, putIfAbsent(T x)方法中的fianl变量list可能连线程安全类都不是,但是对于上面的代码,我们有个假设(当某个链表对象在传递给ImprovedList的构造函数之后,客户代码再也不会使用这个对象,而是使用与其对应的ImprovedList对象),有了这个假设前提,上面的代码就是线程安全的了。

上面就是JAVA并发编程中,在一个已有的线程安全类的基础上添加同步函数的4个方法。

最新文章

  1. 前端er是否忽略了某些东西?——读《ppk谈JavaScript》
  2. Javascript初学篇章_4(循环与函数)
  3. 20169212《Linux内核原理与分析》第七周作业
  4. centos 安装 python2.7 运行webpy 项目
  5. js从0开始构思表情插件
  6. phpwind9.0模板制作教程——制作论坛风格
  7. 安卓手机当Mac、Win和Linux外置WIFI网卡
  8. java数据结构
  9. 报错:&#39;Could not load NIB in bundle: &#39;NSBundle解决办法
  10. google prettify 代码高亮显示
  11. Oracle常用的函数
  12. 腾讯校招技术岗面试经历及总结(已发offer)
  13. WMI查看电脑信息,devenv管理自己的解决方案
  14. atexit()函数
  15. 几个关于js数组方法reduce的经典片段
  16. SQL Server 2008作业失败无法确定所有者是否有服务器访问权限
  17. 课堂动手动脑String
  18. react结合redux开发
  19. 为移动端而设计的bootstrap的使用
  20. leetcode1019

热门文章

  1. org.apache.ibatis.binding.BindingException: Parameter ‘brOrderNo’ not found. Available parameters ar
  2. Python链表
  3. 使用VUE开发微信小程序
  4. C语言运行时数据结构
  5. 抓取豆瓣的电影排行榜TOP100
  6. Matlab 图像的邻域和块操作
  7. 3、Python字典集合
  8. angularjs 事件向上向下传播
  9. SPFA的两种优化
  10. sicily 1000. LinkedList