当任务通过执行器服务提交给线程池中的线程时,如何确保一次只能有一个线程占用一个同步任务?

When task is submitted to threads in a thread pool via executor service how to ensure that only 1 thread can occupy a synchronized task at a time?

我有以下工作人员class -

public class Worker implements Runnable {
    private int workId;

    public Worker(int workId) {
        this.workId = workId;
    }

    private int count = 0;

    private synchronized void increment() {
        System.out.println("Work id: " + workId);
        System.out.println("Incrementing...");
        Thread.sleep(5000);
        count++;
        System.out.println("Incremented");
    }

    @Override
    public void run() {
        increment();
    }
}

我有以下主要方法 -

ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 1; i <= 10; i++) {
            executorService.submit(new Worker(i));
        }
        executorService.shutdown();
        System.out.println("All tasks submitted");
        executorService.awaitTermination(1, TimeUnit.DAYS);
        System.out.println("All tasks completed");

此处increment()已同步。因此,当 1 个线程占用它时,另一个线程必须等到该线程离开锁。

但是当我使用 2 个线程的线程池提交工作时,两个线程似乎同时使用 increment()

那么在这里我如何强制两个线程一次只使用一个increment()方法?

private synchronized void increment() 

此方法锁定在 Object 级别工作,因此如果您有两个对象,它们在调用此方法时不会互相阻塞,因为每个 会调用它自己的 increment()方法(在同一个Worker实例上没有并发调用)。


为了避免不同的实例同时访问increment()方法,你需要Class级别的同步,这是在你所有Worker的锁都相同的情况下实现的实例。声明锁的一些选项:

  • 共享 Object

    public class Boss extends RichDad implements EarnLotsOfMoney
    {
       private final Object masterLock;
       public Boss() 
       {
          masterLock = new Object();
       }
       public Worker createWorker(int slaveId) 
       {
          return new Worker(masterLock, slaveId);
       }
       //...
    }
    

    是的,我知道的愚蠢的例子..

    public class Worker implements Runnable 
    {
       private final Object lock;
       private int workId;
    
       public Worker(Object lock, int workId) 
       {
          this.lock = lock;
          this.workId = workId;
       }
    
       private void increment() 
       {
           synchronized(lock) /*lock holds the same reference in all instances*/
           {
               //...
           }
       }
    
       @Override
       public void run() {
           increment();
       }
    }
    

lock 仅创建一次,然后在创建 Worker 实例时作为参数传递。这将阻止所有 从相同的 Boss 创建的 Worker 个实例( 在这种方法中 lock 是一个非静态对象).


  • 自己的Class

    public class Worker implements Runnable 
    {
       private int workId;
       public Worker(int workId) {
          this.workId = workId;
       }
    
       private int count = 0;
    
       private void increment() 
       {
           synchronized(Worker.class) /*class level lock here*/
           {
             System.out.println("Work id: " + workId);
             System.out.println("Incrementing...");
             Thread.sleep(5000);
             count++;
             System.out.println("Incremented");
           }
       }
    
       @Override
       public void run() {
           increment();
       }
    }
    

这将使用共享 Worker class 作为锁来同步线程。