Java 静态变量与可变变量

Java 静态变量与可变变量,java,multithreading,Java,Multithreading,我只是从线程的角度提问……可能回答了很多次,但请帮助我理解这一点 关于这里的帖子 对于所有线程,询问一个静态变量值也将是一个值,那么为什么我们应该选择volatile呢?我发现了以下例子: public class VolatileExample { public static void main(String args[]) { new ExampleThread("Thread 1 ").start(); new ExampleThread("Thread 2

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

关于这里的帖子

对于所有线程,询问一个静态变量值也将是一个值,那么为什么我们应该选择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();  
          }  
       }  
       }  
       }
如果我从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();
            }
        }
    }
}