gpt4 book ai didi

java - Synchronized 关键字在 Java 中无法按预期工作

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

编辑:我已经在堆栈上找到了答案: https://stackoverflow.com/a/16280842/3319557

我遇到同步问题。我有以下两种方法:

public synchronized void incrementCounter1() {
counter++;
}

public void incrementCounter2() {
synchronized (counter) {
counter++;
}
}

我在多个线程中(单独)测试了其中的每一个。第一个方法的行为符合预期,但第二个方法(incrementCounter2)是错误的。有人可以解释为什么会发生这种情况吗?

我认为这个方法设计得很好,因为我在 Java Concurrency in Practice 中发现了一些类似的东西。摘自本书:

@ThreadSafe
public class ListHelper<E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
...
public boolean putIfAbsent(E x) {
synchronized (list) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}

我使用正在修改的对象的监视器,就像书中一样。

完整代码在这里:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SynchronizationTest {
public static final int N_THREADS = 500;
public static final int N_Loops = 5000;
private Integer counter = 0;
Lock l = new ReentrantLock();

public void incrementCounter0() {
counter++;
}

public synchronized void incrementCounter1() {
counter++;
}

public void incrementCounter2() {
synchronized (counter) {
counter++;
}
}

public void incrementCounter3() {
try {
l.lock();
counter++;
} finally {
l.unlock();
}
}

private interface IncrementStrategy {
void use(SynchronizationTest t);
}

private static class IncrementingRunnable implements Runnable {
SynchronizationTest synchronizationTest;
IncrementStrategy methodToUse;

public IncrementingRunnable(SynchronizationTest synchronizationTest, IncrementStrategy methodToUse) {
this.synchronizationTest = synchronizationTest;
this.methodToUse = methodToUse;
}

@Override
public void run() {
for (int i = 0; i < N_Loops; i++) {
methodToUse.use(synchronizationTest);
}
}

}

public void test(IncrementStrategy methodToUse, String methodName) {
counter = 0;
Thread[] threads = new Thread[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
threads[i] = new Thread(new IncrementingRunnable(this, methodToUse));
threads[i].start();
}
for (int i = 0; i < N_THREADS; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(methodName + " diff than expected " + (counter - N_THREADS * N_Loops));
}

public void test() {
test(t -> t.incrementCounter0(), "incrementCounter0 (expected to be wrong)");
test(t -> t.incrementCounter1(), "incrementCounter1");
test(t -> t.incrementCounter2(), "incrementCounter2");
test(t -> t.incrementCounter3(), "incrementCounter3");
}

public static void main(String[] args) {
new SynchronizationTest().test();
}

}

我知道,应该使用 ExecutorService,整个问题可以用 AtomicLong 解决,但这不是这个问题的重点。

代码的输出是:

incrementCounter0 (expected to be wrong) diff than expected -1831489
incrementCounter1 diff than expected 0
incrementCounter2 diff than expected -599314
incrementCounter3 diff than expected 0
PS。如果我将该字段添加到 SynchronizationTest

Object counterLock = new Object();

并改变将Counter2增量为:

public void incrementCounter2() {
synchronized (counterLock) {
counter++;
}
}

然后 incremetCounter2 按预期工作。

最佳答案

您正在不同的对象上进行同步

incrementCounter1this 上同步,而 incrementCounter2 在计数器 Integer 对象本身上同步。

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

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