首页 > 解决方案 > 在 int 变量上使用时,volatile 关键字的行为不符合预期

问题描述

import java.util.ArrayList;

public class ThreadTest {

    public static void main(String[] args) {

        ArrayList arr = new ArrayList();        
        for (int  i =0; i<10 ; i++)
            arr.add(new MyTh(i));   
        for (int  i =0; i<10 ; i++) {
            ((Thread ) arr.get(i)).start();
        }
    }

}

class MyTh extends Thread {

   int num;

   volatile int  age;

   MyTh (int  k)

   {this.num=k; } 
   @Override
   public void run() {
    if(this.num==4){
        setAge(40);
    }
    System.out.println(Thread.currentThread().getName() + " :"+this.num + ":" + getAge());
}
    synchronized int getAge() {
       return age;
    }
    synchronized void  setAge(int  k) {
        this.age =k;
    }
}

我在这里感到困惑,为什么程序的输出只打印一次 volatile 变量 age = 40 的值。我尝试在 getter/setter 中保持同步,然后也只有单线程 4th 打印 40。为什么其他后续线程也不读 40 呢?

Thread-0 :0:0
Thread-1 :1:0
Thread-2 :2:0
Thread-3 :3:0
Thread-4 :4:40
Thread-5 :5:0
Thread-6 :6:0
Thread-7 :7:0
Thread-8 :8:0
Thread-9 :9:0

标签: javamultithreadingvolatile

解决方案


为什么synchronized在声明变量时为 getter 和 setter 使用关键字volatile。这里不需要。你只需要可见性,而不是原子性。所以像这样改变你的代码,

public class MyTh extends Thread {
    int num;

    static volatile int age;

    MyTh(int k)

    {
        this.num = k;
    }

    @Override
    public void run() {
        if (this.num == 4) {
            setAge(40);
        }
        System.out.println(Thread.currentThread().getName() + " :" + this.num + ":" + getAge());
    }

    int getAge() {
        return age;
    }

    void setAge(int k) {
        age = k;
    }
}

首先将age变量标记为,static以便在类的所有实例之间共享该变量。在您之前的情况下,它是一个实例字段,因此每个实例都有自己的副本。因此,一个人所做的更改对其他人是不可见的。

最新输出如下。

Thread-0 :0:0
Thread-3 :3:0
Thread-2 :2:0
Thread-1 :1:0
Thread-4 :4:40
Thread-6 :6:40
Thread-8 :8:40
Thread-5 :5:40
Thread-7 :7:40
Thread-9 :9:40

推荐阅读