Java volatile修饰符实际功能的疑问,大家看看为什么会这样?
本帖最后由 carrd2008 于 2013-05-30 12:51:58 编辑 public class ThreadTest implements Runnable {
String s;
volatile int c;
public ThreadTest(String s) {
this.s = s;
}
public void run() {
for (int i = 0; i < 10; i++) {
c ++;
System.out.println(this.s + ":" + c);
try {
if ("Thread1".equals(s)) {
Thread.sleep(500);
} else {
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Thread(new ThreadTest("Thread1")).start();
new Thread(new ThreadTest("Thread2")).start();
}
以上代码的某一次的执行结果是:
Thread1:1
Thread2:1
Thread1:2
Thread1:3
Thread1:4
Thread1:5
Thread2:2
Thread1:6
Thread1:7
Thread1:8
Thread2:3
Thread1:9
Thread1:10
Thread2:4
Thread2:5
Thread2:6
Thread2:7
Thread2:8
Thread2:9
Thread2:10
从结果看出,Thread1和Thread2这两个线程内部对变量c的运算没有互相影响。
也就是说,每次修改c,都没有跟主存进行同步。
而资料上说:volatile的功能是用于把工作内存中的副本同步到主存中,这样这个线程对变量的修改针对其他线程达到可视的效果。也就是变量共享。
但我的例子中,我用了volatile修饰符,但变量还是没有起到共享的目的。
请问这是为什么?
是我的例子写的有问题吗? Java 多线程 volatile
[解决办法]
2个线程运行2个不同的实例,内部变量c是不会影响的。
new Thread(new ThreadTest("Thread1")).start();
new Thread(new ThreadTest("Thread2")).start();
要么将
volatile int c;
改成static的
static volatile int c;
要么使用一个实例
package cn.sax.test;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
final ThreadTest t = new ThreadTest("");
new Thread(t, "Thread1").start();
new Thread(t, "Thread2").start();
}
static class ThreadTest implements Runnable {
volatile int c;
public ThreadTest(String s) {
}
public void run() {
final String threadName = Thread.currentThread().getName();
for (int i = 0; i < 10; i++) {
c++;
System.out.println(threadName + ":" + c);
try {
if ("Thread1".equals(threadName)) {
Thread.sleep(500);
} else {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
但是以上的修改还是有问题的
虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。
所以不赞成使用volatile进行累加,一般最好是用来改变boolean的数值。