解读【Java theory and practice: Managing volatility】
来源:互联网 发布:戴尔软件下载中心 编辑:程序博客网 时间:2024/05/16 07:26
原文链接:Java theory and practice: Managing volatility
要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值。
该变量没有包含在具有其他变量的不等式中。
即假设volatile变量为n,那么不应有n++,n>m等用法。
volatile的错误用法1
public class VolatileTest { public static volatile int count = 0; public static void main(String[] args) { // 同时启动1000个线程,去进行i++计算,看看实际结果 Thread threads[] = new Thread[1000]; for (int i = 0; i < 1000; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { // 这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } count++; //increase(); } }); threads[i].start(); } // 等待所有线程结束 try { for (int i = 0; i < 1000; i++) { threads[i].join(); } } catch (InterruptedException e) { e.printStackTrace(); } // 这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:count=" + count); } public static synchronized void increase() { // 进入和退出synchronized块或方法时,会同步线程的临时变量与内存主变量。保证count的值的正确性。 count++; }}
上述代码运行时,我们期望的结果是1000,可惜实际运行时结果并不一定是1000。
正确的做法是将count++替换成同步方法increase。
由于同步方法会自动同步线程的缓存与主内存中的变量,所以此时count变量无需设为volatile。
volatile的错误用法2
public class VolatileTest2 { private volatile int lower = 0; private volatile int upper = 10; public void setLower(int value) { if (value > upper) throw new IllegalArgumentException(); lower = value; } public void setUpper(int value) { if (value < lower) throw new IllegalArgumentException(); upper = value; } public void test() { new Thread(new Runnable() { @Override public void run() { setLower(5); System.out.println("lower:" + lower + ",upper:" + upper); } }).start(); new Thread(new Runnable() { @Override public void run() { setUpper(3); System.out.println("lower:" + lower + ",upper:" + upper); } }).start(); } public static void main(String[] args) { new VolatileTest2().test(); }}
上述代码运行时,我们期望的结果是出Exception。
如果第8行lower=value和第13行upper=value上打上断点,就会出现我们不希望出现的结果。lower:5,upper:3
正确的做法时将setLower和setUpper改成同步方法。
应该使用volatile的场合:
public class VolatileTest3 { private long temp = 0x7fffffff00000000L; private boolean running = true; public void test() { Thread t1 = new Thread(new Runnable() { @Override public void run() { long a; while (running) { a = temp; if (a != 0x7fffffff00000000L && a != 0x00000000ffffffffL) { System.out.println(Long.toHexString(a)); } } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { temp = 0x7fffffff00000000L; } running = false; } }); Thread t3 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { temp = 0x00000000ffffffffL; } running = false; } }); t1.start(); t2.start(); t3.start(); } public static void main(String[] args) { new VolatileTest3().test(); }}
上述代码的运行结果,我们期望是没有输出,但是实际运行结果是有输出。输出0或7fffffffffffffff,每次运行结果都不一样。
正确的做法是将temp变量变为volatile。
- 解读【Java theory and practice: Managing volatility】
- Java theory and practice
- Java theory and practice: Hashing it out
- Java theory and practice: Good housekeeping practices
- Java theory and practice: Safe construction techniques
- (泛型)Java theory and practice: Generics gotchas
- Theory and Practice
- Java theory and practice: Thread pools and work queues
- XML in Theory and Practice
- Web Services: Theory and Practice
- Game Design: Theory and Practice
- Systems Modelling: Theory and Practice
- Modern Cryptography: Theory and Practice
- Software Engineering: Theory and Practice
- (java)正确使用volatile变量(managing volatility)
- Software Evolution and Feedback: Theory and Practice
- (Development)Software Engineering:Theory and Practice
- Resources for Reinforcement Learning: Theory and Practice
- bzoj 1600
- 编程路上第一天
- 关于linux下部署javaWeb项目
- ORA-13600 QSM-00794错误处理
- H面试程序(25):在一个字符串中删除特定字符
- 解读【Java theory and practice: Managing volatility】
- LeetCode | Swap Nodes in Pairs
- DTD学习
- [xcode]Error launching remote program: failed to get the task for process xxx 本人解决办法
- 合法字符串——庞果网
- Ext.Net LayOut
- Java 数组的总结
- java 中 ckeditor 的使用
- Lucida Grande字体无法正常显示冒号的解决方案