Java 静态变量与可变变量
我只是从线程的角度提问……可能回答了很多次,但请帮助我理解这一点 关于这里的帖子 对于所有线程,询问一个静态变量值也将是一个值,那么为什么我们应该选择volatile呢?我发现了以下例子:Java 静态变量与可变变量,java,multithreading,Java,Multithreading,我只是从线程的角度提问……可能回答了很多次,但请帮助我理解这一点 关于这里的帖子 对于所有线程,询问一个静态变量值也将是一个值,那么为什么我们应该选择volatile呢?我发现了以下例子: public class VolatileExample { public static void main(String args[]) { new ExampleThread("Thread 1 ").start(); new ExampleThread("Thread 2
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();
}
}
}
}
如果我从testValue中删除static,则会得到以下结果:
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示例的链接,其中该变量不是声明静态的
感谢使用
volatile
是为了确保所有线程同时看到相同的值。本质上,它是说这个变量永远不应该被缓存
很难在代码中演示,因为缓存策略会随着cpu和JRE的变化而变化
volatile
对JRE说的是,如果您试图缓存这个值,因为您认为这样做可以使代码运行得更快一些<不要强>。。。我对编程的了解比你多得多,我毫不怀疑地知道,如果你这样做,你会破坏我的代码。问题是++不是原子的。代码应改用AtomicInteger
。使用static
变量,两个线程都试图更新相同的值,++实际上是3个操作:get、+1和store。这意味着两个线程之间都存在竞争条件,并且它们正在相互覆盖
为什么线程2没有读取更新的值?如果它必须是静态的,那么volatile有什么用呢
static
和volatile
做不同的事情<代码>静态使字段与类关联,而不是与对象实例关联<代码>易失性强制字段的任何读取或写入跨越内存屏障。这允许多个线程读取和更新公共字段,但这并不能保护您免受多个操作的影响。如果您使变量不是静态的,那么您就不需要volatile
,因为每个线程都将使用它自己的字段实例
您应该使用AtomicInteger
。这包装了一个volatile int
,但也提供了对增量操作的特殊处理:
private static AtomicInteger testValue = new AtomicInteger(1);
...
testValue.incrementAndGet();
有没有人能给出一个很好的volatile示例的链接,其中该变量不是声明静态的
当多个线程共享非静态字段时,您需要在该字段上设置一个
volatile
。例如,如果您将testValue
向上移动到VolatileExample
类中,然后将VolatileExample
类的相同实例传递到两个线程中,以便它们可以访问testValue
,在这种情况下,当您删除静态
修饰符时,您更改了变量,因为现在,每个ExampleThread
都有自己的testValue
,因此,每个线程实例的存储值都不同
静态
修饰符的含义:
有时,您希望拥有对所有对象通用的变量。这是通过“静态”修改器完成的。声明中包含静态修饰符的字段称为静态字段或类变量。它们与类相关联,而不是与任何对象相关联。类的每个实例都共享一个类变量,该变量位于内存中的一个固定位置。任何对象都可以更改类变量的值
参考:
关于volatile
,如果尝试其他类型的测试,请将testValue
变量移动到类VolatileExample
,如下所示:
public class VolatileExample {
private volatile int testValue = 1;
...
}
然后,从ExampleThread
中删除testVariable
,并运行代码。它的输出应该和第一个一样
volatile
修饰语的含义:
使用易失性变量可以降低内存一致性错误的风险,因为对易失性变量的任何写入都会与该变量的后续读取建立“发生在之前”的关系。这意味着对易失性变量的更改对其他线程总是可见的
参考资料:您的最后一个问题
“有人能给出一个很好的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();
}
}
}
}
public类volatile示例{
//公共静态volatile int testValue=1;
公共int非静态=8;
公共静态void main(字符串参数[]){
VolatileExample VolatileExample=新的VolatileExample();
新的示例线程(“线程1”,volatileExample).start();
新的示例线程(“线程2”,volatileExample).start();
}
}
类ExampleThread扩展线程{
VolatileExample VolatileExample;
公共示例线程(字符串str,VolatileExample VolatileExample){
超级(str);
this.volatileExample=volatileExample;
}
公开募捐{
对于(int i=0;i<3;i++){
试一试{
if(getName().compareTo(“线程1”)==0)
{
volatileExample.nonstatic++;
System.out.println(“测试值T1:+volatileExample.nonstatic”);
}
if(getName().compareTo(“线程2”)==0)
{
System.out.println(“测试值T2:+挥发性示例非静态”);
睡眠(1);
}
//睡眠(1000);
}捕获(中断异常异常){
异常。printStackTrace();
}
}
}
}
现在请通过公开int nonstatic=8来查看更改;易变的
以下是使其不稳定时的输出
测试值T1:9
测试值T1:10
测试值T1:11
测试值T2:
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();
}
}
}
}