-1

我打算将一些代码与一些全局变量并行化。我将使用 ReentrantReadWriteLock。我是否理解正确,我需要为每个变量创建一个自己的 ReentrantReadWriteLock 实例,以确保线程安全?

我的意思是,当我有两个列表时,每个线程都可以附加一个项目,并且所有线程有时都从该列表中读取项目。在那种情况下,我会实现类似的东西:

private static String[] globalVariables = null;
private static String[] processedItems = null;

private final ReentrantReadWriteLock globalVariablesLock = new ReentrantReadWriteLock();
private final Lock globalVariablesEeadLock  = globalVariablesLock .readLock();
private final Lock globalVariablesWriteLock = globalVariablesLock .writeLock();
private final ReentrantReadWriteLock processedItemsLock = new ReentrantReadWriteLock();
private final Lock processedItemsLockReadLock  = processedItemsLock .readLock();
private final Lock processedItemsLockWriteLock = processedItemsLock .writeLock();

如果我有更多变量,例如数据库连接(池)、记录器、更多列表等,该怎么办?

我需要制作一个新的 ReentrantReadWriteLock 还是我遗漏了什么?互联网上的样本只处理一个变量。

提前致谢。

4

3 回答 3

1

你想保护什么?

不要想锁定变量。锁的目的是保护不变量不变量是您可以对程序状态做出的一些断言,该断言必须始终为真。例如,“变量 A、B 和 C 的总和将始终为零”。

在这种情况下,为 A、B 和 C 设置单独的锁对您没有任何好处。您需要一个锁来保护该特定不变量。任何想要更改 A、B 或 C 的线程都必须锁定该锁,并且任何依赖于它们的总和为零的线程都必须锁定同一个锁。

通常,如果不暂时破坏某些不变量,线程就不可能取得进展。例如,

A += 1;    //breaks the invariant
B -= 1;    //fixes it again.

如果没有同步,其他线程可能会检查这两个语句之间的 A、B 和 C,并发现不变量被破坏。

同步:

private final Object zeroSumLock = new Object();

void bumpA() {
    synchronized(zeroSumLock) {
        A += 1;
        B -= 1;
    }
}

boolean verifySum() {
    synchronized(zeroSumLock) {
        return (A+B+C) == 0;
    }
}
于 2015-10-21T13:58:18.060 回答
0

Lock是的,每个线程安全变量(在您的情况下为数组)都应该有一个。但是,考虑使用

ArrayList<String> syncList = Collections.synchronizedList(new ArrayList<String>());

而不是数组。当您委托给库时通常会更好(在这种情况下,不仅是同步,还有数组的调整大小)。当然,在执行此操作之前,请检查该库是否完全符合您的预期(在这种情况下,正如@SashaSalauyou 指出的那样,您将失去同时阅读的能力)。

于 2015-10-21T12:16:06.397 回答
0

一种解决方案是创建一个 immutable Map,您可以在其中为您需要的所有项目添加锁:

final static Map<String, ReadWriteLock> locks = Collections.unmodifiableMap(
     new HashMap<String, ReadWriteLock>() {{
         put("globalVariables", new ReentrantReadWriteLock());
         put("processedItems",  new ReentrantReadWriteLock());
         // rest items
     }}
);

由于 HashMap 被包装Collections.unmodifiableMap(),因此无法修改,它成为线程安全的。

然后,在代码中:

Lock lo = locks.get("globalVariables").readLock();
lo.acquire();
try {
    // ...
} catch (Exception e) {
    // ...
} finally {
    lo.release();
}
于 2015-10-21T12:21:13.273 回答