在集中位置锁定交易



我有以下情况:


public class LockingScenario {
public static final ConcurrentHashMap<String, Vector<Task>>BUFFER = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Object>LOCKS = new ConcurrentHashMap<>();
private static final Object SURROGATE = new Object();
public void bufferTransaction(Context ctx) {
String transaction = ctx.getTransaction();
Object obj = LOCKS.putIfAbsent(transaction, SURROGATE);
Vector<Task>tasks;
Iterator<String>it = LOCKS.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
if (key.equals(transaction)) {
transaction = key;
}
}
//minimize the case when there will be created useless Vector objects.
if (obj == null) {
tasks = new Vector<>();
BUFFERS.putIfAbsent(transaction, tasks);
}
syncrhonized(transaction) {
tasks = BUFFERS.get(transaction);
}
//... create task
tasks.add(task);
// ... 
}
public void finishTransaction(Context ctx) {
String transaction = ctx.getTransaction();
Vector<Task>tasks = BUFFER.get(transaction);
// finish job here...
}
}

我试图在这里解释一下上面的代码及其上下文:

LockingScenario是受管 Bean 的类,它由不同的线程访问,这些线程启动不同的事务。每个事务都有一个唯一的编号和许多与之关联的要执行的任务。

我面临以下问题:我需要锁定一部分代码,该代码在许多线程之间共享一些内存,为许多事务发送许多任务,这些事务必须由托管 Bean 处理(该 Bean 实际上可以有多个托管实例)。

问:对于这种情况,是否有更好的方法?这假设我的方法是正确的(我的意思是它没有错)。

重要提示:在上述场景中,您应该只考虑bufferTransaction及其上面的代码。下面的代码实际上在不同的托管 Bean 中。我把它放在那里让你了解整个画面。

我很确定你可以简单地这样做:

class LockingScenario {
private static final Map<String, Vector<Task>> BUFFER = new ConcurrentHashMap<>();
public void bufferTransaction(Context ctx) {
String transaction = ctx.getTransaction();
Vector<Task> tasks;
// prevent creation of two Vectors for the same transaction
synchronized (BUFFER) {
tasks = BUFFER.get(transaction);
if (tasks == null) {
tasks = new Vector<>();
BUFFER.put(transaction, tasks);
}
}
// create tasks and put into Vector
tasks.add(createTask());
}
}

任务列表检索/创建速度足够快,您可以在这段时间内阻塞整个缓冲区。

对于Java 8,您将使用

synchronized (BUFFER) {
tasks = BUFFER.computeIfAbsent(transaction, s -> new Vector<>());
}

尽管@daniu的答案很好,但我只想指出 OP 中的代码包含竞争条件。

在波纹管片段中:


while (it.hasNext()) {
String key = it.next();
if (key.equals(transaction)) {
transaction = key;
}
}
//minimize the case when there will be created useless Vector objects.
if (obj == null) { // point 1
tasks = new Vector();
BUFFERS.putIfAbsent(transaction, tasks);
}
syncrhonized(transaction) { // point 2
tasks = BUFFERS.get(transaction);
}
//... create task
tasks.add(task); // point 3

您可以看到,在point 3,由于来自point 1的争用条件,可能会出现不可预测的行为。在线程(我们称之为线程 A)尝试初始化tasksVector之前,另一个线程可以继续前进并在线程 A 执行此操作之前point 2获取锁,并且第二个线程访问假定创建的Vector,它可以创建一半或根本不创建。

最新更新