gpt4 book ai didi

java - 为什么这里的volatile和synchronized语句无法避免线程干扰呢?

转载 作者:行者123 更新时间:2023-12-03 01:50:51 25 4
gpt4 key购买 nike

package simple;

public class ThreadInterference {
public static volatile Integer count = 1000;

public static class MyThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
count++;
count--;
count++;
count--;
}
}
}

public static void main(String[] args) throws InterruptedException {
System.out.println(count);

Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
Thread t3 = new Thread(new MyThread());
Thread t4 = new Thread(new MyThread());

t1.start();
t2.start();
t3.start();
t4.start();

t1.join();
t2.join();
t3.join();
t4.join();

System.out.println(count);

}

}

count 变量被标记为 volatile ,但输出为:

1000
1230

如果我更改为synchronized语句,也会发生线程干扰:

package simple;

public class ThreadInterference {
public static Integer count = 1000;

public static class MyThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
synchronized(count) {
count++;
count--;
count++;
count--;
}
}
}
}

public static void main(String[] args) throws InterruptedException {
System.out.println(count);

Thread t1 = new Thread(new MyThread());
Thread t2 = new Thread(new MyThread());
Thread t3 = new Thread(new MyThread());
Thread t4 = new Thread(new MyThread());

t1.start();
t2.start();
t3.start();
t4.start();

t1.join();
t2.join();
t3.join();
t4.join();

System.out.println(count);

}

}

本次的输出为:

1000
1008

为什么?

最佳答案

正如其他人所指出的,您有两个不同的问题。第一个是 count++ (和 count--)不是原子操作,即使对于原始 int 类型也是如此。因此,如果没有某种锁定或其他并发处理,这将无法工作。对于 count++(其中 count 是 int),编译器会生成类似于以下字节码指令的内容:

    getstatic count
iconst_1
iadd
putstatic count

即使编译为 native 代码,这也不太可能是原子的。

第二个问题是您没有锁定一致的对象,因此操作没有序列化。代码:

   count++; // "count" is an "Integer" object type.

创建一个新对象。本质上它做了如下的事情:

   count = Integer.valueOf(count.intValue() + 1);

因此,您的 count 对象将被新对象替换,随后进入 synchronized 部分将针对不同的对象进行同步。

作为安全提示,如果您使用 synchronized (someObject),其中 someObject 是类或实例字段,那么最好将该字段设置为 最终。这样就不会无意中将其重新分配给不同的值。

我能想到的问题有两种简单的解决方案。一种针对用于锁定的特定对象进行锁定的方法,如下所示:

public class ThreadInterference {
public static final Object COUNT_LOCK = new Object();
public static int count = 1000; // Either "int" or "Integer" OK, depending on need

public static class MyThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
synchronized(COUNT_LOCK) {
count++;
count--;
count++;
count--;
}
}
}
}

// And so on...
}

另一种选择是使用 AtomicInteger ,它可以提供更好的并发性能(如果重要的话):

public class ThreadInterference {
public static AtomicInteger count = new AtomicInteger(1000);

public static class MyThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
count.incrementAndGet();
count.decrementAndGet();
count.incrementAndGet();
count.decrementAndGet();
}
}
}

// And so on...
}

关于java - 为什么这里的volatile和synchronized语句无法避免线程干扰呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25925306/

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