当前位置: 首页 > 知识库问答 >
问题:

是否使引用变量易失性,使其所有字段在java中也易失性?

燕和同
2023-03-14

我已经读到,使引用变量易失性,并不会使其内部字段易失性。但我尝试了下面的示例,其中看起来易失性也应用于类的内部字段。

使用者java:-//字段“flag”设置为true的用户类。

public class User {

    private boolean flag=true;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
} 

MyRunnableThread1。java:-

在这里,我将“user”设置为volatile,而不是将其内部字段“flag”设置为volatile

子线程在“while(this.user.isFlag())”处连续处于循环中。

public class MyRunnableThread1 implements Runnable {

    private String threadName;
    private  volatile User  user; 

    public MyRunnableThread1(String threadName,User user)
    {
        this.threadName=threadName; 
        this.user=user;
    } 

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public void run() {

        System.out.println("child thread:"+threadName+" started");

        while(this.user.isFlag()) {

        }
        System.out.println("child thread:"+threadName+" finished");
    }
}

线程演示。java:-

在主线程中,我们将“User”对象的“flag”字段的值设置为false,以终止子线程中的循环

public class ThreadDemo {

    public static void main(final String[] arguments) throws InterruptedException {

        System.out.println("main thread started");

        User user=new User(); 
        MyRunnableThread1 myRunnableThread1=new MyRunnableThread1("Thread1",user);
        Thread t=new Thread(myRunnableThread1);
        t.start();

        try {
            Thread.sleep(6000);
        }
        catch(Exception e) {
            System.out.println("exception in sleep:"+e);
        }

        myRunnableThread1.getUser().setFlag(false);

        System.out.println("main thread finished"); 
    }
}

订单号:-

主线程已启动子线程:线程1已启动主线程已完成子线程:线程1已完成

在上面的示例中,我将“user”变量设置为“MyRunnableThread1.java”类中的volatile。用户对象具有字段“flag”,该字段在实例化时为true。在启动连续执行循环的子线程后,主线程将用户对象的字段“flag”的值更改为false。但此处字段“flag”不是易失性的,而“user”引用变量是易失性的。但在这里,主线程中“flag”字段值的变化仍反映在子线程中。它的行为就好像字段“flag”也是可变的。有人能帮助解决上述问题吗??

共有3个答案

章涵蓄
2023-03-14

不要假设声明引用volatile可以保证引用对象成员的安全发布。

当引用是可变的且缺乏线程安全性时,其他线程可能会看到部分构造的对象或处于不一致状态的对象。

当引用不可变时,声明引用volatile就足以保证引用成员的安全发布。不能使用volatile来保证可变对象的安全发布。使用volatile只能保证原语字段、对象引用或不可变对象引用的字段的安全发布。

只有在一组受限的情况下,才能使用volatile变量而不是锁。volatile变量必须满足以下两个标准,以提供所需的线程安全性:

  • 对变量的写入不取决于其当前值
  • 该变量不参与其他变量的不变量

总结:

<代码>用户是可变的,一个<代码>线程设置<代码>标志值并不保证新值对另一个<代码>线程可见。

选项1:使用volatile标志:

public class User {
    private volatile boolean flag = true;
} 

选项2:使用原子布尔:

public class User {
    private final AtomicBoolean flag = new AtomicBoolean(true);

    public boolean isFlag() {
        return flag.get();
    }

    public void setFlag(boolean flag) {
        this.flag.set(flag);
    }
} 

选项3:使用同步:

public class User {
    private boolean flag = true;

    public synchronized boolean isFlag() {
        return flag;
    }

    public synchronized void setFlag(boolean flag) {
        this.flag = flag;
    }
} 
段干子晋
2023-03-14

您总是通过引用实例来访问成员:

this.user.is标志

这样,您的循环包含对易失性变量user的读取,并且循环的主体没有得到优化。

尝试在循环之前获取对局部变量的实例引用,您将看到不同之处。

例如。:

    User u = this.user;
    while(u.isFlag())
    {

    }
傅嘉悦
2023-03-14

来自JLS:

8.3.1.4易失性场

Java编程语言允许线程访问共享变量(§17.1)。通常,为了确保共享变量得到一致、可靠的更新,线程应该通过获取锁来确保独占使用这些变量,按照惯例,锁会强制这些共享变量互斥。

Java编程语言提供了第二种机制,volatile字段,在某些方面比锁定更方便。

一个字段可以被声明为易失性,在这种情况下,Java内存模型确保所有线程都看到变量的一致值(§17.4)。

但对象不是变量。那么在您的情况下,一致的是user的值,这意味着所有线程都看到相同的引用,而不是它们观察到的内部内容的值相同。

 类似资料:
  • 我对下面的代码段有一个问题。结果可能有一个结果[0,1,0](这是用JCStress执行的测试)。那么这是怎么发生的呢?我认为数据写入(data=1)应该在Actor2(guard2=1)中写入到guard2之前执行。我说得对吗?我问,因为很多时候我读到挥发物周围的说明没有重新排序。此外,根据这一点:http://tutorials.jenkov.com/java-concurrency/vola

  • 所有的中断函数都能正常工作,但是过程函数却让我很生气。 我会感激任何我没注意的把戏。

  • 来自C/C++,我对Java中的volatile对象行为有点困惑。 null faik,volatile意味着b引用的“book对象”应该在主内存中。编译器可能在内部实现引用作为指针,因此b指针可能位于缓存中。我的理解是,volatile是对象的限定符,而不是引用/指针的限定符。 问题是:在使用方法中,本地引用不是易失性的。这个“本地”引用会不会把底层的Book对象从主存带到缓存中,实质上使对象不

  • 当线程读取易失性变量时,它不仅会看到易失性的最新更改,还会看到导致更改的代码的副作用 这是在http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html提到的 有人可以举个例子吗? 这首先给我的印象是,读取可变变量的线程将与编写器线程同步,并等待写入完成。但事实显然并非如此。 举个例子会很有帮助,非常感谢。 谢谢,

  • 我正在使用以下字段: 哪里 这样发布日期图安全吗?我的意思是,易失性字段意味着对一个字段的引用不会缓存在CPU寄存器中,并且在任何时候访问它都可以从内存中读取。 因此,我们不妨为映射的

  • 在阅读了这个问题和这个(尤其是第二个答案)之后,我对volatile及其关于记忆障碍的语义感到非常困惑。 在上面的例子中,我们写入一个易失性变量,这会导致一个mitch,这反过来会将所有挂起的存储缓冲区/加载缓冲区刷新到主缓存,使其他缓存行无效。 然而,非易失性字段可以优化并存储在寄存器中,例如?那么,我们如何才能确保给定一个写入易失性变量之前的所有状态变化都是可见的呢?如果我们有1000件东西呢