我有以下情况:
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)尝试初始化tasks
Vector
之前,另一个线程可以继续前进并在线程 A 执行此操作之前point 2
获取锁,并且第二个线程访问假定创建的Vector
,它可以创建一半或根本不创建。