我想知道为什么这个结果不是 1000000



我用线程池创建了 100 个线程,加了钱,用了 synced,但结果没有达到 1000000。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(100);
for(int i=0;i<100;i++) {
Thread t=new MyThread();
pool.execute(t);
}
pool.shutdown();
}
}
class MyThread extends Thread{
private static int money=0;
@Override
public void run() {
addMoney();
}
public synchronized void addMoney() {
for(int i=0;i<10000;i++)
money+=1;
System.out.println(money);
}
}

添加到addMoney方法的synchronized关键字使用this作为内部锁。由于this指向每个线程实例,并且每个线程仅调用此方法一次,因此它不起作用。

要跨线程同步访问,您可以显式指定全局锁实例,例如ThreadPool类:

public void addMoney() {
synchronized(ThreadPool.class) {
for(int i=0;i<10000;i++)
money+=1;
System.out.println(money);
}
}

在您的情况下,通过将addMoney方法声明为static来实现几乎相同的结果。在这种情况下,内部锁将是MyThread类:

public static synchronized void addMoney() {
for(int i=0;i<10000;i++)
money+=1;
System.out.println(money);
}

您可以在 Java 文档中找到更多详细信息 https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

问题是在访问和更新共享静态变量时,您的每个任务都在不同的对象上同步。 这意味着工作线程之间没有互斥。 这意味着应用程序计算的值可能是不可预测的和/或特定于平台的。 (除非你运气好...

解决此问题的一种方法是将addMoney更改为static synchronized方法。 这将导致线程在MyThread.class对象上同步。 但是,如果您这样做,您会发现您的应用程序实际上是单线程的......因为一次只有一个MyThread实例能够执行其addMoney方法。

目前尚不清楚正确的修复程序是什么,因为不清楚这个"玩具"示例试图演示什么。 但是我提到的替代方法至少应该可靠地计算结果。


您不应该扩展Thread。 您的MyThread类应替换为实现Runnable的类。 您在这里要做的是使用Thread对象,就好像它只是一个Runnable一样。 这是个坏主意。 您正在使用的ExecutorService将负责线程创建。 您需要为它提供"任务"而不是"线程"。

最新更新