静态变量与易失性

我只是以线程的角度提问……可能已经回答了很多次,但请帮助我理解这一点。

参考java中的 post Volatile Vs Static

要求一个静态变量值也将是所有线程的一个值,那么我们为什么要选择volatile呢? 我找到了以下示例:

public class VolatileExample { public static void main(String args[]) { new ExampleThread("Thread 1 ").start(); new ExampleThread("Thread 2 ").start(); } } class ExampleThread extends Thread { private static volatile int testValue = 1; public ExampleThread(String str){ super(str); } public void run() { for (int i = 0; i < 3; i++) { try { System.out.println(getName() + " : "+i); if (getName().compareTo("Thread 1 ") == 0) { testValue++; System.out.println( "Test Value T1: " + testValue); } if (getName().compareTo("Thread 2 ") == 0) { System.out.println( "Test Value T2: " + testValue); } Thread.sleep(1000); } catch (InterruptedException exception) { exception.printStackTrace(); } } } } 

输出:

 Thread 1 : 0 Test Value T1: 2 Thread 2 : 0 Test Value T2: 2 Thread 1 : 1 Test Value T1: 3 Thread 2 : 1 Test Value T2: 3 Thread 1 : 2 Test Value T1: 4 Thread 2 : 2 Test Value T2: 4 

如果我从testValue中删除静态,结果是:

 Thread 1 : 0 Test Value T1: 2 Thread 2 : 0 Test Value T2: 1 Thread 1 : 1 Test Value T1: 3 Thread 2 : 1 Test Value T2: 1 Thread 1 : 2 Test Value T1: 4 Thread 2 : 2 Test Value T2: 1 

为什么线程2没有读取更新的值? 如果它必须是静态的,那么使用volatile是什么?

有人可以链接到volatile的一个很好的例子,其中该变量未声明为静态。

谢谢

问题是++不是primefaces的。 代码应该使用AtomicInteger 。 使用static变量,两个线程都尝试更新相同的值,而++实际上是3个操作:get,+ 1和store。 这意味着两个线程之间存在竞争条件,并且它们会相互覆盖。

为什么线程2没有读取更新的值? 如果它必须是静态的,那么使用volatile是什么?

staticvolatile做不同的事情。 static使与该类关联的字段与对象实例相对。 volatile强制任何字段的读取或写入穿过内存屏障。 这允许多个线程读取和更新公共字段,但这不会保护您免受多个操作的影响。 如果你使变量不是静态的,那么你就不需要volatile因为每个线程都会使用它自己的字段实例。

您应该使用AtomicInteger 。 这包装了一个volatile int但也提供了增量操作的特殊处理:

 private static AtomicInteger testValue = new AtomicInteger(1); ... testValue.incrementAndGet(); 

有人可以链接到volatile的一个很好的例子,其中该变量未声明为静态。

当多个线程共享非静态字段时,您需要一个volatile 。 例如,如果您将testValue移动到VolatileExample类中,然后将VolatileExample类的相同实例传递到两个线程中,以便它们可以访问testValue

volatile的使用是为了确保所有线程同时看到相同的值。 基本上它是说永远不应该缓存这个变量。

在代码中很难演示,因为缓存策略从cpu变为cpu,从JRE变为JRE。

对JRE说什么volatile 如果你想要缓存这个值,因为你认为你可以通过这样做让代码运行得更快…… 不要! …我对编程的了解比你知道得多,而且毫无疑问,我知道如果你这样做,你将破坏我的代码。

在这种情况下,当tou删除static修饰符时,您更改了变量,因为现在每个ExampleThread都有自己的testValue ,为此,每个线程实例的存储值都不同。

static修饰符的含义:

有时,您希望拥有所有对象共有的变量。 这是通过静态修改器完成的。 在声明中具有static修饰符的字段称为静态字段或类变量。 它们与类相关联,而不是与任何对象相关联。 该类的每个实例共享一个类变量,该变量位于内存中的一个固定位置。 任何对象都可以改变类变量的值……

参考: 了解实例和类成员

关于volatile ,如果你尝试不同类型的测试,将testValue变量移动到类VolatileExample ,如下所示:

  public class VolatileExample { private volatile int testValue = 1; ... } 

然后,从ExampleThread删除ExampleThread并运行代码。 它的输出应该像第一个一样。

volatile修饰符的含义:

使用volatile变量可以降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系。 这意味着对volatile变量的更改始终对其他线程可见

参考: primefaces访问

你的上一个问题“有人可以链接到一个很好的volatile变量示例,其中变量不是静态的。” 为了清楚地理解这个概念,我带来了一个例子。

  public class VolatileExample { // public static volatile int testValue = 1; public int nonstatic=8; public static void main(String args[]) { VolatileExample volatileExample=new VolatileExample(); new ExampleThread("Thread 1 ",volatileExample).start(); new ExampleThread("Thread 2 ",volatileExample).start(); } } class ExampleThread extends Thread { VolatileExample volatileExample; public ExampleThread(String str,VolatileExample volatileExample){ super(str); this.volatileExample=volatileExample; } public void run() { for (int i = 0; i < 3; i++) { try { if (getName().compareTo("Thread 1 ") == 0) { volatileExample.nonstatic++; System.out.println( "Test Value T1: " + volatileExample.nonstatic); } if (getName().compareTo("Thread 2 ") == 0) { System.out.println( "Test Value T2: " + volatileExample.nonstatic); Thread.sleep(1); } // Thread.sleep(1000); } catch (InterruptedException exception) { exception.printStackTrace(); } } } } 

现在请通过公开int nonstatic = 8看到变化; 挥发物

以下是挥发时的输出,

测试值T1:9测试值T1:10测试值T1:11测试值T2:11测试值T2:11测试值T2:11

进程以退出代码0结束

如果它是非易失性的,则结果如下:测试值T1:9测试值T2:9测试值T1:10测试值T1:11测试值T2:11测试值T2:11

进程以退出代码0结束

观察:由于Volatile keyWord使线程直接将其写入主内存,因此线程更快地返回到循环,因此当它变为volatile时,thread1更快地完成其任务并且甚至在thread2开始之前返回到循环。

另一方面,使其成为非易失性,使线程更新其locl缓存,然后将其报告给主内存...因此在此循环期间,thread2进入竞争。

PLZ注意,我在VolatileExample类中有“非静态”变量而不是在ExampleThread中来演示这个变量。

您的另一个问题是:为什么线程2没有读取更新的值? 如果它必须是静态的,那么使用volatile是什么?

好吧,如果你让它的testvalue非静态,那么它只是两个不同的对象,类ExampleThread的Thread1和Thread2工作在他们自己的varibles testvalue ....所以不稳定并不重要..