我有以下情况:
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中。我把它放在那里让你全面了解。
答案 0 :(得分:2)
我很确定你可以这样做:
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<>());
}
答案 1 :(得分:0)
虽然@ 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
,可以创建一半或根本不创建。