gpt4 book ai didi

java - 没有 static 的 volatile 关键字无法按预期工作

转载 作者:行者123 更新时间:2023-11-30 02:47:25 25 4
gpt4 key购买 nike

我理解了变量的 volatile 和 static 关键字之间的区别。

静态变量可以由不同的实例更改,而 volatile 变量可以由不同的线程更改。

但是如果我删除 MY_INT 变量的 static 关键字,下面的程序(从互联网复制并稍作修改)就会挂起。

即使没有 static 关键字,其他线程也应该可以看到变量 MY_INT 的更新。但如果我删除静态它就会挂起。

请帮助我理解这个问题。

public class PrintOddAndEven extends Thread {
static volatile int i = 1;

Object lock;

PrintOddAndEven(Object lock) {
this.lock = lock;
}

public static void main(String ar[]) {
Object obj = new Object();
PrintOddAndEven odd = new PrintOddAndEven(obj);
PrintOddAndEven even = new PrintOddAndEven(obj);
odd.setName("Odd");
even.setName("Even");
odd.start();
even.start();
}

@Override
public void run() {
while (i <= 10) {
if (i % 2 == 0 && Thread.currentThread().getName().equals("Even")) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - " + i);
i++;
lock.notify();
}
}
if (i % 2 == 1 && Thread.currentThread().getName().equals("Odd")) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - " + i);
i++;

try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

最佳答案

您的错误是由于以下事实造成的:如果您从字段 i 中删除 static 关键字,您将拥有一个不同字段i 每个实例 PrintOddAndEven 因此,这里由于您有 2 实例,因此您有2 个不同的字段 i 使得 Even 线程将永远循环,因为它的 i 永远不会被修改,并且 Odd 线程会等待出于同样的原因永远。当您将字段声明为static时,线程共享同一字段i,这样您就不会遇到错误。

您应该创建一个专用类来保存计数器,并使用它的一个实例作为对象监视器,您将在 PrintOddAndEven 实例之间共享该对象监视器,如下所示:

public class MyClass {
volatile int i = 1;
}

public class PrintOddAndEven extends Thread {

MyClass lock;

PrintOddAndEven(MyClass lock) {
this.lock = lock;
}

public static void main(String[] args) throws Exception {
MyClass obj = new MyClass();
PrintOddAndEven odd = new PrintOddAndEven(obj);
PrintOddAndEven even = new PrintOddAndEven(obj);
odd.setName("Odd");
even.setName("Even");
odd.start();
even.start();
}

@Override
public void run() {
while (lock.i <= 10) {
if (lock.i % 2 == 0 && Thread.currentThread().getName().equals("Even")) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - " + lock.i);
lock.i++;
lock.notify();
}
}
if (lock.i % 2 == 1 && Thread.currentThread().getName().equals("Odd")) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " - " + lock.i);
lock.i++;

try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
<小时/>

如果您只有一个计数器,您还可以考虑使用 AtomicInteger 类的实例作为计数器和对象监视器。代码与上面相同,只是您将使用 new AtomicInteger(1) 创建一个实例,将计数器初始化为 1,然后使用 get() 获取当前值,incrementAndGet() 增加计数器。

关于java - 没有 static 的 volatile 关键字无法按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39744418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com