为什么这段代码中没有发生同步?

Why isn't synchronization taking place in this code?

package atask;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Q3Synchronization 
{
    Integer sum=new Integer(0);

     Q3Synchronization(){
         ExecutorService e=Executors.newFixedThreadPool(1000);
         for(int i=0;i<1000;i++){
             e.execute(new Sum());
         }
         e.shutdown();

         while(!e.isTerminated()){

         }
         System.out.println(sum);
     }
    public static void main(String[]args){
        new Q3Synchronization();
    }

     class Sum implements Runnable{


        @Override
        public void run() {

            m();

        }
       public synchronized void m(){
             sum=sum+1;
         }
     }

}

问题是:

简而言之

对象方法 synchronization/locking 在每个实例的基础上工作。

说明

您正在创建 Sum class 的 1000 个实例。对 m() 的每次调用都是同步的,但不会导致任何其他线程等待。这是因为没有对同一实例的并发调用,而是对不同实例的调用。我附上了你的代码,稍作改动:

     Sum s = new Sum();
     for(int i=0;i<1000;i++){
         e.execute(s);
     }

如果您尝试此更改,您将始终在计数器变量中得到 1000 的结果。

在构造函数中,您正在创建 new Sum() 实例并将其传递给单独的线程。 m() 方法正在获取对象上的锁(每个线程在进入同步块时都必须获取锁)。因此每个线程都可以同时执行 m() 方法,这会破坏您的多线程逻辑,因为 (sum = sum + 1) 不是原子操作。

您可以修复它:

  1. 将 sum 变量更改为 Atomic Integer 并使用 addAndGet() 执行加法。例如

AtomicInteger sum= new AtomicInteger(0);

和方法m使用原子整数

public void m(){sum.addAndGet(1);}

2.Use 同一个对象获取锁,这样 m 方法就会正确同步。您可以通过在构造函数中创建一个 sum 实例变量来实现它,例如 .

final Sum sum = new Sum();
for (int i = 0; i < 1000; i++) {
    `e.execute(sum);
}