- 浏览: 837943 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
loveseed1989:
您好,我用您的方法运行Cone.java,会给我报java.l ...
vtk学习笔记 --- 编译vtk库和java库 -
60love5:
60love5 写道首先谢谢你的解析,但你这个验证可见性的小程 ...
多线程中共享对象的可见性 -
60love5:
首先谢谢你的解析,但你这个验证可见性的小程序是存在问题的,你的 ...
多线程中共享对象的可见性 -
Gamehu520:
...
java 中的Unsafe -
shanpao1234560:
这个list不是静态的第一种情况下也会有线程安全的问题么,求指 ...
一个看似线程安全的示例
在《java并发编程实战》第四章4.4.1节给出了一个程序示例:
@NotThreadSafe class BadListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }
这个示例希望实现的功能是为List提供一个原子操作:若没有则添加。因为ArrayList本身不是线程安全的,所以通过集合Collections.synchronizedList将其转换为一个线程安全的类,然后通过一个辅助的方法来为List实现这么个功能。初看起来这个方法没问题,因为也添加了synchronized关键字实现加锁了。
但是仔细分析,你会发现问题。首先对于synchronized关键字,需要说明的是,它是基于当前的对象来加锁的,上面的方法也可以这样写:
public boolean putIfAbsent(E x) { synchronized(this) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }
所以这里的锁其实是BadListHelper对象, 而可以肯定的是Collections.synchronizedList返回的线程安全的List内部使用的锁绝对不是BadListHelper的对象,所以BadListHelper中的putIfAbsent方法和线程安全的List使用的不是同一个锁,因此上面的这个加了synchronized关键字的方法依然不能实现线程安全性。
下面给出书中的另一种正确的实现:
@ThreadSafe class GoodListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x) { synchronized (list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } } }
如果你要分析这个实现是否正确,你需要搞清楚Collections.synchronizedList返回的线程安全的List内部使用的锁是哪个对象,所以你得看看Collections.synchronizedList这个方法的源码了。该方法源码如下:
public static <T> List<T> synchronizedList(List<T> list) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<T>(list) : new SynchronizedList<T>(list)); }
通过源码,我们还需要知道ArrayList是否实现了RandomAccess接口:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
查看ArrayList的源码,可以看到它实现了RandomAccess,所以上面的synchronizedList放回的应该是SynchronizedRandomAccessList的实例。接下来看看SynchronizedRandomAccessList这个类的实现:
static class SynchronizedRandomAccessList<E> extends SynchronizedList<E> implements RandomAccess { SynchronizedRandomAccessList(List<E> list) { super(list); } SynchronizedRandomAccessList(List<E> list, Object mutex) { super(list, mutex); } public List<E> subList(int fromIndex, int toIndex) { synchronized(mutex) { return new SynchronizedRandomAccessList<E>( list.subList(fromIndex, toIndex), mutex); } } static final long serialVersionUID = 1530674583602358482L; /** * Allows instances to be deserialized in pre-1.4 JREs (which do * not have SynchronizedRandomAccessList). SynchronizedList has * a readResolve method that inverts this transformation upon * deserialization. */ private Object writeReplace() { return new SynchronizedList<E>(list); } }
因为SynchronizedRandomAccessList这个类继承自SynchronizedList,而大部分方法都在SynchronizedList中实现了,所以源码中只包含了很少的方法,但是通过subList方法,我们可以看到这里使用的锁对象为mutex对象,而mutex是在SynchronizedCollection类中定义的,所以再看看SynchronizedCollection这个类中关于mutex的定义部分源码:
static class SynchronizedCollection<E> implements Collection<E>, Serializable { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 3053995032091335093L; final Collection<E> c; // Backing Collection final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection<E> c) { if (c==null) throw new NullPointerException(); this.c = c; mutex = this; } SynchronizedCollection(Collection<E> c, Object mutex) { this.c = c; this.mutex = mutex; } }
可以看到mutex就是当前的SynchronizedCollection对象,而SynchronizedRandomAccessList继承自SynchronizedList,SynchronizedList又继承自SynchronizedCollection,所以SynchronizedRandomAccessList中的mutex也就是SynchronizedRandomAccessList的this对象。所以在GoodListHelper中使用的锁list对象,和SynchronizedRandomAccessList内部的锁是一致的,所以它可以实现线程安全性。
发表评论
-
基于Oracle Streams + Oracle AQ 捕获变更,发布变更(二)
2014-11-21 22:23 3164要求:使用Oracle Streams捕获某个用户下部 ... -
基于Oracle Streams + Oracle AQ 捕获变更,发布变更(一)
2014-11-20 22:23 2715要求:使用Oracle Streams捕获某个用户下部分表 ... -
如何去掉在浏览器中打开java applet时的警告对话框
2013-08-24 12:10 6948好久没更新博客了! 最近,由于项目要求,需要将sw ... -
Android 内存泄露笔记
2013-03-05 23:10 01、大部分内存泄露都是错误的持有了Activity或者Con ... -
java 虚拟机总结 【思维导图】
2012-12-22 20:11 2055java虚拟机总结思维导图: 参考《深入理解jav ... -
Java虚拟机字节码执行引擎 【思维导图】
2012-12-22 19:51 1593java虚拟机字节码执行引擎思维导图总结: 参考《深入理 ... -
java 垃圾回收相关总结 【思维导图】
2012-12-21 19:03 3237java垃圾回收相关总结: 参考《深入理解java ... -
java并发中的延迟初始化
2012-12-12 19:17 4641在《java并发编程实战 ... -
java同步容器与并发容器
2012-12-09 18:07 4300何为同步容器:可以简 ... -
多线程中的long和double
2012-12-08 19:26 4125在看一些代码的时候,会发现在定义long型和double型的 ... -
多线程中共享对象的可见性
2012-12-08 18:52 5059在阅读《java并发编程实战》的第三章的时候,看到书中的一个 ... -
一个快速、轻量级 Collection 库 Trove
2012-12-07 09:35 3695Trove一个快速、轻量级针对java原子类型(byte,i ... -
java 中的Unsafe
2012-12-05 22:25 32673在阅读AtomicInteger的源码时,看到了这个类:su ... -
在ubuntu10上编译Thrift0.8.0
2012-08-01 15:34 2104下载thrift0.8.0 ,地址: http:// ... -
生活小工具--记账小助手1.0发布
2012-05-31 15:08 1647因为自己平时喜欢记账,把每日的消费情况都记录下来,所以希望找 ... -
话费速查升级版v1.3发布
2012-05-04 12:47 1377前段时间开发了一个话费速查的小应用,最近一直保持每周更新一个 ... -
编译zeromq的java绑定:jzmq
2012-05-03 22:47 134911、 下载zeromq源码:http://www.ze ... -
Android软件包静默安装小应用 - 附源码
2012-04-21 20:50 12345老早之前,写了一个android软件包静默安装的应用,放在工 ... -
最方便的联通话费,余额查询软件来了! --- 联通话费速查v1.2
2012-04-12 18:01 3954软件介绍: 联通话费速查是一款针对联通 ... -
android开发之定制标题栏 --- 附源码
2012-04-11 21:53 12086在开发上个应用 话费 ...
相关推荐
这是一个多线程的示例工程,非常适合新手学习! 这是一个多线程的示例工程,非常适合新手学习! 这是一个多线程的示例工程,非常适合新手学习! 这是一个多线程的示例工程,非常适合新手学习! 这是一个多线程的示例...
C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例C#多线程示例
Java 多线程 订票 示例 线程安全 Demo 例子 经典
简单多线程编程入门,可以帮助你实现第一个多线程程序
VC++ 线程优先级 示例程序 VC++线程优先级示例程序-赛马,不同优先级执行的程序显示在进度条中,有长有短,像赛马一样,体现出每个线程被执行的优先顺序。
VisualC 实效编程 61 线程优先级示例-赛马VisualC 实效编程 61 线程优先级示例-赛马VisualC 实效编程 61 线程优先级示例-赛马VisualC 实效编程 61 线程优先级示例-赛马VisualC 实效编程 61 线程优先级示例-赛马...
答:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。 在多线程...
多核课程 多线程优先级示例_赛马 通过例子来演示多线程优先级
servlet线程安全问题servlet线程安全问题
Thread本质上也是一个实现了Runnable的实例,他代表一个线程的实例,并且启动线程的唯一方法就是通过Thread类的start方法。 2.实现Runnable接口,并实现该接口的run()方法.创建一个Thread对象,用实现的Runnable接口...
这是一个源代码项目,通过很明了的代码来向大家诠释什么叫做线程安全,怎样才能达到线程安全,已经怎样去避免非线程安全问题
这是一个C# winform的多线程操作示例,可以参考解决界面卡死问题
等线程示例学习等线程示例学习等线程示例学习等线程示例学习等线程示例学习等线程示例学习
C# 的多线程排序示例 C# 的多线程排序示例 C# 的多线程排序示例 C# 的多线程排序示例 适合初学者使用
mysql是线程不安全的,mysql不是线程安全的,多线程共用同一个mysql连接是会崩溃的 QT的QSqlDatabase是基于mysql的,所以一样是线程不安全的 现讲明mysql为什么是线程不安全的,以及在多线程环境下如何使用mysql,...
示例设置日志线程每个1分钟收集,3个任务线程处理的日志,写入log文件到本地。 3个任务线程在处理完任务后,继续开启新线程进行任务处理,但总数不超过设置的线程阀值。示例阀值为3. 喜欢多线程的朋友,不妨一起...
今天没事给大家写一个多线程例子 今天没事给大家写一个多线程例子
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 ) : https://hanshuliang.blog.csdn.net/article/details/102851323 下载完项目后 , 使用 Visual Studio 打开 , 注意需要配置 POSIX 线程库 ( 参考以下博客配置...
MFC窗口程序多线程示例 MFC窗口程序多线程示例 MFC窗口程序多线程示例
支持多线程: 多个线程某时刻下载同一个文件的不同块. 2. 断点续传: 如果下载了一个文件的某些块(一半), 则下次下载时只需下载未完成的块;文件块的下载状态用控制文件记录. 块下载完成的先后顺序不一定是连续的....