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;
}
我有一个这样的 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;
}