【问题标题】:not getting the desired result in ExecutorService在 ExecutorService 中没有得到想要的结果
【发布时间】:2021-05-28 18:04:59
【问题描述】:

为什么我没有将 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 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

这里有什么问题?

【问题讨论】:

  • 点击 pastebin 链接..无法在此处发布整个代码..
  • 可能是因为 ArrayList 不是线程安全的
  • 但是我在同步块中调用它..所以没关系..可能是不同的原因?
  • 它必须是线程安全的,因为如果我这样做List&lt;Integer&gt; list1 = Collections.synchronizedList(new ArrayList&lt;&gt;()) 并且与 list2 相同,那么它总是 1000。自己尝试一下,不要相信我的话 :) 如果我确切地知道为什么我会把它作为一个答案
  • 我想这与你使用两把锁有关。

标签: java multithreading executorservice


【解决方案1】:
 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-14
    • 2022-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多