ExecutorService 公平性

ExecutorService fairness

我有一个这样的 ExecutorService

ExecutorService executor =  new ThreadPoolExecutor(threads, threads,
            0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1000, true));

我正在使用 .execute(Runnable)

向它发送工作

我的可运行文件有

        @Override
        public void run() {
            this.processor.performAction(this);
        }

处理器有

public void performAction(RunnableAction action) {
        Lock lock = lockManager.getLock(action.getId());
        lock.lock();
        try {
            action.execute();
        } finally {
            lock.unlock();
        }
    }

锁管理器在哪里

public class LockManager {

    Map<String, Lock> lockById = new HashMap<>(1000);

    public synchronized Lock getLock(String id) {
        Lock lock = lockById.get(id);
        if (lock == null) {
            lock = new ReentrantLock(true);
        }
        return lock;
    }

和我的 actions/runnable 有一个 execQty 字段,它触发一些订单的更新调用他们的 order.execute(execQty)

public void execute(int execQty) {
        if (execQty < this.lastExecQty) {
            System.err.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            System.err.println("id: " + this.id + " wrong order" + this.lastExecQty + " > " + execQty);
        }
        this.execQty += execQty;
        this.lastExecQty = execQty;
    }
}

我已经命令我的 runnables 发送到调度程序,并且每个 qty 字段都比前一个大,所以在将每个 runnable 发送到 ExecutorService 之前打印每个 runnable 时,我总是得到我需要的,有序的数字:

execute: id: 49  qty: 819
execute: id: 49  qty: 820
execute: id: 49  qty: 821
execute: id: 49  qty: 822
execute: id: 49  qty: 823

但即使我的 ExecutorService 由公平队列支持,并且我在每个实体更新之前使用每个实体锁,它似乎仍然没有按顺序更新实体

execute: id: 88  qty: 6
execute: id: 88  qty: 7
execute: id: 88  qty: 8
execute: id: 88  qty: 9
execute: id: 88  qty: 10
execute: id: 88  qty: 11
execute: id: 88  qty: 12
execute: id: 88  qty: 13
execute: id: 88  qty: 14
execute: id: 88  qty: 15
execute: id: 88  qty: 16
execute: id: 88  qty: 17
execute: id: 88  qty: 18
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
id: 88 wrong order 17 (previous) > 7 (current)
execute: id: 88  qty: 19
execute: id: 88  qty: 20

当 运行 只有一个线程的 ExecutorService

时它工作正常

您的 LockManager 似乎不正确。您永远不会将这些锁放入地图中,因此您总是在新对象上进行同步。

建议的更改:

public synchronized Lock getLock(String id) {
    Lock lock = lockById.get(id);
    if (lock == null) {
        lock = new ReentrantLock(true);
        // put lock into the map so that next one will reuse it
        lockById.put(id, lock);
    }
    return lock;
}