静态变量与易失性
我只是以线程的角度提问……可能已经回答了很多次,但请帮助我理解这一点。
参考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是什么?
static
和volatile
做不同的事情。 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 ....所以不稳定并不重要..