据我所知,如果我们将一个变量声明为volatile,那么它将不会存储在本地缓存中。每当线程更新这些值时,它都会更新到主存中。因此,其他线程可以访问更新后的值。
但是在下面的程序中,易失性变量和非易失性变量显示的值是相同的。
不更新第二个线程的易失性变量。有人能解释一下为什么testValue没有改变吗?
class ExampleThread extends Thread {
private int testValue1;
private volatile int testValue;
public ExampleThread(String str){
super(str);
}
public void run() {
if (getName().equals("Thread 1 "))
{
testValue = 10;
testValue1= 10;
System.out.println( "Thread 1 testValue1 : " + testValue1);
System.out.println( "Thread 1 testValue : " + testValue);
}
if (getName().equals("Thread 2 "))
{
System.out.println( "Thread 2 testValue1 : " + testValue1);
System.out.println( "Thread 2 testValue : " + testValue);
}
}
}
public class VolatileExample {
public static void main(String args[]) {
new ExampleThread("Thread 1 ").start();
new ExampleThread("Thread 2 ").start();
}
}output:
Thread 1 testValue1 : 10
Thread 1 testValue : 10
Thread 2 testValue1 : 0
Thread 2 testValue : 0发布于 2010-04-15 19:30:35
您的变量被限制在单个线程中,因此没有其他线程访问它们。因此,volatile没有什么不同。
如果您将它们声明为static,则它们将在不同的线程之间共享。但是,即使这样,您也可能无法观察到易失性变量和非易失性变量之间的差异。引用自Java Concurrency in Practice,第3.1.4章:
易失性变量的可见性影响超出了易失性变量本身的值。当线程A写入易失性变量,随后线程B读取该变量时,在写入易失性变量之前对A可见的所有变量的值在读取易失性变量之后对B变为可见。因此,从内存可见性的角度来看,编写易失性变量就像退出同步块,读取易失性变量就像进入同步块。
在本例中,代码碰巧首先修改了易失性变量,因此另一个变量的更新值可能对另一个线程不可见。到现在为止还好。
但是,由于您是从修改变量的同一线程中打印出变量的值,所以您将看不到任何区别。
Update2:尝试这个修改过的版本(注意:我还没有测试过它):
class ExampleThread extends Thread {
private static int testValue1;
private static volatile int testValue;
private int newValue;
public ExampleThread(String str, int newValue){
super(str);
this.newValue = newValue;
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + " testValue1 before update: " + testValue1);
System.out.println(getName() + " testValue before update: " + testValue);
testValue = i * newValue;
testValue1 = i * newValue;
System.out.println(getName() + " testValue1 after update: " + testValue1);
System.out.println(getName() + " testValue after update: " + testValue);
sleep(10);
}
}
}
public class VolatileExample {
public static void main(String args[]) {
new ExampleThread("Thread 1 ", 5).start();
new ExampleThread("Thread 2 ", 10).start();
}
}更新:关于静态字段可见性的-同样来自同一本书(第16.2.3章):
...静态初始化的对象在构造期间或被引用时都不需要显式同步。但是,这仅适用于构造状态-如果对象是可变的,则读取器和写入器仍需要同步,以使后续修改可见并避免数据损坏。
发布于 2010-04-15 19:35:09
这与volatile无关;这是两个独立的ExampleThread实例,它们有自己的testValue1和testValue副本,它们是实例字段(而不是static类变量,它们在所有实例之间“共享”)。
发布于 2010-04-15 19:31:29
ExampleThread 1和ExampleThread 2是不同的对象。
在其中一个示例中,您将10赋给了两个int字段,这就是为什么您会看到第一线程输出。
在第二种情况下,你没有给int字段赋值,所以你得到0。
https://stackoverflow.com/questions/2644771
复制相似问题