浏览 4515 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2014-12-01
最后修改:2014-12-03
public class Main { private long count; private ExecutorService pool; private Lock lock = new ReentrantLock(); /** * @param args */ public static void main(String[] args) { new Main().countThread(); } public Main() { pool = Executors.newFixedThreadPool(50); } public void countThread() { for (int i = 0; i < 3000; i++) { pool.execute(new Runnable() { @Override public void run() { lock.lock(); try { count++; } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }); } while (true) { System.out.println(count); if (count == 3000) { break; } } System.out.println(count); pool.shutdown(); } } http://www.infoq.com/cn/articles/java-memory-model-1 这篇文章介绍了Java内存模型定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。 能不能这样理解,类中的全局变量是存储在主内存。也就是读操作不需要锁,不知道理解是否正确。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2014-12-05
主存的变量,线程的本地内存会有一个副本这没错.可是两者有一个同步时机的问题,所以你这样用是不安全的.
要么两边都同步保护,要么你增加"volatile"关键字提示这个变量不能创建本地副本. |
|
返回顶楼 | |
发表时间:2014-12-08
etnet 写道 主存的变量,线程的本地内存会有一个副本这没错.可是两者有一个同步时机的问题,所以你这样用是不安全的.
要么两边都同步保护,要么你增加"volatile"关键字提示这个变量不能创建本地副本. 这几天看了下这方面的知识,其实这个程序虽然读是非线程安全,但是写是线程安全的,但站在业务角度来说,此程序是完全没有问题的,因为读线程每次读到的count值会一直是小于3000,但只要等写线程执行完毕,读线程还是能够取到正确值。 |
|
返回顶楼 | |
发表时间:2014-12-08
2楼正解
只需要将 private long count; 改写为 private volatile long count; 即可 要说本质 就需要看jmm了,主要是因为各个cpu都有L1 等缓存,缓存跟内存间会出现不同步问题,而volatile会保证各个cpu缓存内容跟内存一致,而sychonized 则会在退出同步区时将缓存数据刷回内存从而保证 内存一致性。 哈哈 如有不对,多多指教啦 |
|
返回顶楼 | |
发表时间:2015-01-08
如果你的业务场景对一致性没有要求。也就是说,可以容忍count增加后另外一根线程读到增加之前的count值,那么是没有问题的。
|
|
返回顶楼 | |
发表时间:2015-01-10
smartgear 写道 如果你的业务场景对一致性没有要求。也就是说,可以容忍count增加后另外一根线程读到增加之前的count值,那么是没有问题的。
呵呵,是的,我现在明白了我这个写法其实是使用了下面这篇文章里面描述的“开销较低的读-写锁策略” http://www.ibm.com/developerworks/cn/java/j-jtp06197.html |
|
返回顶楼 | |
发表时间:2015-03-27
最后修改:2015-03-27
MauerSu 写道 2楼正解
只需要将 private long count; 改写为 private volatile long count; 即可 要说本质 就需要看jmm了,主要是因为各个cpu都有L1 等缓存,缓存跟内存间会出现不同步问题,而volatile会保证各个cpu缓存内容跟内存一致,而sychonized 则会在退出同步区时将缓存数据刷回内存从而保证 内存一致性。 哈哈 如有不对,多多指教啦 你说的我也同意,但是我看java concurrency in practice中介绍说 必须满足以下所有条件才能使用 volatile关键字 1:只有一个线程对变量进行修改;或者 对变量的写入不依赖当前值 2:该变量不会与其他变量一起纳入不变性条件 3:访问该变量时候不需要加锁 你这样在lock的代码中用volatile关键字 显然违法了第三点啊。 还是我理解有误 请指正 |
|
返回顶楼 | |
发表时间:2015-03-28
oncelonly 写道 MauerSu 写道 2楼正解
只需要将 private long count; 改写为 private volatile long count; 即可 要说本质 就需要看jmm了,主要是因为各个cpu都有L1 等缓存,缓存跟内存间会出现不同步问题,而volatile会保证各个cpu缓存内容跟内存一致,而sychonized 则会在退出同步区时将缓存数据刷回内存从而保证 内存一致性。 哈哈 如有不对,多多指教啦 你说的我也同意,但是我看java concurrency in practice中介绍说 必须满足以下所有条件才能使用 volatile关键字 1:只有一个线程对变量进行修改;或者 对变量的写入不依赖当前值 2:该变量不会与其他变量一起纳入不变性条件 3:访问该变量时候不需要加锁 你这样在lock的代码中用volatile关键字 显然违法了第三点啊。 还是我理解有误 请指正 第三条 3:访问该变量时候不需要加锁 这句话我认为 其语境 意思 表达的是 :‘当不存在 多个线程并发访问的时候’ 也就是书中这句话的意思 没有多线程访问情况,也就不需要加锁,感觉翻译有问题 |
|
返回顶楼 | |