在 ExecutorService 中没有得到想要的结果

not getting the desired result in ExecutorService

为什么我没有将 list1 和 list2 的列表大小设置为 1000 在下面的代码中:

https://pastebin.com/ttcbkjqR

我的主要方法代码如下:

    ExecutorService executor = Executors.newFixedThreadPool(2);

    for(int j=0; j<2; j++) {
        executor.submit(new Worker(j));
    }

    executor.shutdown();
    System.out.println("All tasks submitted: ");

    try {
        executor.awaitTermination(1, TimeUnit.DAYS);
    } catch (InterruptedException e) {

    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken: " + (end - start));
    System.out.println("List1: " + list1.size() + "; List2: " + list2.size());

这里是 Worker class:

class Worker implements Runnable{
    private int id;
    
    public Worker(int id) {
        this.id = id;
    }

    private Random random = new Random();
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    public void stageOne() {
        synchronized(lock1) {
            try {
                Thread.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            WorkerThreadPool.list1.add(random.nextInt(100));
        }
    }

    public void stageTwo() {
        synchronized(lock2) {
            try {
                Thread.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            WorkerThreadPool.list2.add(random.nextInt(100));
        }
    }

    public void process() {
        for(int i=0; i<500; i++) {
            stageOne();
            stageTwo();
        }
    }

    @Override
    public void run() {
        System.out.println("Starting thread: " + id);
        process();     
        System.out.println("Completed: " + id);   
    }
}

一次运行我得到

List1: 986; List2: 989

我得到的其他时间

List1: 994; List2: 981

但每次都应该给

List1: 1000; List2: 1000

这是怎么回事?

 class Worker implements Runnable{
    
        private int id;
        
        public Worker(int id) {
            this.id = id;
        }
    
        private Random random = new Random();

        private final Object lock1 = new Object();
        private final Object lock2 = new Object();

       .....

结果不可预测,因为线程没有共享锁。

在这里,lock1lock2 没有任何用处。

原因是:当您使用 executor.submit(new Worker(j));WorkerThreadPool 中提交任务时,每个线程都会获得自己的 locks 副本(每个 Worker 实例都会创建新的 lock1lock2).

这里更新了 WorkersharedLock 逻辑:

class Worker implements Runnable {

    private int id;
    Object sharedLock;

    public Worker(int id, Object sharedLock) {
        this.id = id;
        this.sharedLock = sharedLock;
    }

    private Random random = new Random();

    public void stageOne() {

        try {
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        synchronized (sharedLock) {
            WorkerThreadPool.list1.add(random.nextInt(100));
        }
    }

    public void stageTwo() {

        try {
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        synchronized (sharedLock) {
            WorkerThreadPool.list2.add(random.nextInt(100));
        }
    }

    public void process() {
        for (int i = 0; i < 500; i++) {
            stageOne();
            stageTwo();
        }
    }

    @Override
    public void run() {
        System.out.println("Starting thread: " + id);
        process();
        System.out.println("Completed: " + id);
    }

}

已更新WorkerThreadPool

public class WorkerThreadPool {

    public static List<Integer> list1 = new ArrayList<>();
    public static List<Integer> list2 = new ArrayList<>();

    static Object sharedLock = new Object(); // share lock

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

        ExecutorService executor = Executors.newFixedThreadPool(2);

        for (int j = 0; j < 2; j++) {
            executor.submit(new Worker(j, sharedLock)); // pass same lock to each instance of Worker
        }

        executor.shutdown();
        System.out.println("All tasks submitted: ");

        try {
            executor.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {

        }
        long end = System.currentTimeMillis();

        System.out.println("Time taken: " + (end - start));
        System.out.println("List1: " + list1.size() + "; List2: " + list2.size());
    }

}

输出:

All tasks submitted: 
Starting thread: 1
Starting thread: 0
Completed: 0
Completed: 1
Time taken: 1842
List1: 1000; List2: 1000