我正在使用同步方法用Java编写一个同步计数器。代码如下
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Counter implements Runnable {
private static int counter = 0;
private static final int limit = 1000;
private static final int threadPoolSize = 5;
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
for (int i = 0; i < threadPoolSize; i++) {
executorService.submit(new Counter());
}
executorService.shutdown();
}
@Override
public void run() {
incrementCounter();
}
private synchronized void incrementCounter() {
while (counter < limit) {
System.out.println(Thread.currentThread().getName() + " : " + counter);
counter++;
}
}
}
代码运行良好。但在某些时候,两个线程打印相同的数字,
pool-1-thread-2 : 29
pool-1-thread-2 : 30
pool-1-thread-1 : 30
pool-1-thread-1 : 32
如上面的输出所示,线程 2 和 1 都在打印 30
。我不知道为什么会发生这种情况。任何帮助表示赞赏
最佳答案
当您使用synchronized
方法时,执行该方法的线程将获得Counter
类的当前实例的锁定,以便其他线程可以同时递增 >计数器
值没有任何抑制。
这是因为您在循环内创建了 Counter
类的五个不同实例:
for (int i = 0; i < threadPoolSize; i++) {
executorService.submit(new Counter());
}
因此,有时五个线程可以同时执行 incrementCounter()
方法,因为它们锁定了 Counter 类的五个不同实例(当您使用 synchonized
方法,您实际上锁定了 this
或当前类实例)。
您可以创建一个新的静态
锁对象,该对象必须同步
,以便池中的所有线程都拥有并共享相同的公共(public)锁定对象:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
class Counter implements Runnable {
private static AtomicInteger counter = new AtomicInteger(0);
private static final Object lock = new Object();
private static final int limit = 1000;
private static final int threadPoolSize = 5;
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
for (int i = 0; i < threadPoolSize; i++) {
executorService.submit(new Counter());
}
executorService.shutdown();
}
@Override
public void run() {
incrementCounter();
}
private void incrementCounter() {
synchronized (lock) {
while (counter.get() < limit) {
System.out.println(Thread.currentThread().getName() + " : " + counter.get());
counter.incrementAndGet();
}
}
}
}
此外,由于您正在执行读取-更新-写入操作,因此您应该考虑使用AtomicInteger
代替int
> 原语使操作原子,即操作将在单个事务中发生,并且其他线程始终可以看到最新值。
关于Java同步计数器不同线程打印相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57347443/