0

我正在编写一个应用程序来模拟图书市场。

考虑一本名为“BookA”的书,其中包含以下数据:

                       45   47  50  51  55    70  73  75  79 81

**Bookstore1 Buy Qty**  2   3   5   11  1   
**Bookstore2 Buy Qty**  1   3   5   1   10

**Bookstore1 Sell Qty**                       1   11  7   8  20
**Bookstore2 Sell Qty**                       2   5   2   5  10

                             **Data for BookA**

数值数据存储为volatile int[][] dataStorage = new int[5][10]row[0] 包含价格的位置。

row[1] ..row[4] 包含每个书店的可用数量。例如,row[1]col[0] 表示以 45 美元的价格,Bookstore1 愿意购买 2 份 BookA。类似地,row[4][5] 表示 Bookstore2 愿意以 70 美元出售 2 本。

我的市场上有大约 500 本书,每本书的数据都存储在 ConcurrentHashMap 中:(ConcurrentMap<String, int[][]> map = new ConcurrentHashMap<String, int[][]>(500)

“BookA”----> int[][]

“Bookn”----> int[][]

Bookstore1 和 Bokstore2 中的数据通过两个单独的线程到达。目前,我将原始数据对象存储在阻塞队列中,并使用单个线程(“ProcessingThread”)来创建和修改(在更新的情况下)上述数组。

在此处输入图像描述

最后,我的客户在一个单独的线程(“CustomerThread”)中向我发送购买/出售书籍的订单。

一个典型的订单如下所示:“以 50 美元购买 3 份 BookA”:

收到订单后,我执行以下操作:

1) 检查地图是否包含键“BookA”。

2) 如果是,那么我在持有ReadLock (ReentrantReadWriteLock.ReadLock) 的同时克隆 BookA 的数据 (int[][])。

3)然后我遍历克隆数据以找到价格和总数量。

我的问题是:

a)有人可以确认我不需要同步生产者(“ProcessingThread”)。由于 dataStorage (int[][]) 仅由“ProcessingThread”线程更改。此外,由于 dataStorage 是易失的,因此当我写入它时将建立一个“之前发生”(因此,“CustomerThread”将看到最新更新的数据)。

b) 是否有更好的(比使用锁更具可扩展性)方法来确保“Cu​​stomerThread”中的线程安全?我可以通过使用 AtomicIntegerArray 逃脱吗?

谢谢

4

1 回答 1

1

我在这里看到了一些麻烦。您的数组是易变的,但元素不是。只有一个线程修改元素,你在那里是安全的。但是您不能保证 CustomerThread 会看到元素更改。此外,即使元素本身易变的(不容易做到),数组也会发生点点滴滴的变化,并且 CustomerThread 很容易看到不完整的数据。

第一个解决方案是对每个阵列进行适当的锁定。然后 CustomerThread 必须等到完整的数组准备就绪。(多个 CustomerThreads 可以让您解决一本书阻止对其他书籍的操作的问题,我认为这不会使您的并发问题变得更糟。)

另一种解决方案是替换整个数组而不是修改它们。数组实际上是不可变的。从一组数据到下一组数据的变化是瞬时的,并且数据始终是一致的。现在,数组引用是 volatile的事实确保了更改将立即对 CustomerThread 可见,而现在不必等待锁定。

我喜欢第二种解决方案,它更能回答你的问题 B。(原子往往很昂贵。如果你可以用一把原子替换一把锁,那么你就遥遥领先,但如果你用 100 把锁替换一把锁原子,甚至只有 10 个,你都落后了。)

但是,我有点担心多个订单进来的结果。如果还剩一本书,你不想卖给 5 个不同的人。在我看来,从您所写的内容来看,CustomerThread 上的订单和从阻塞队列进入 ProcessingThread 的信息需要仔细同步。ProcessingThread 和 CustomerThread 都是一个线程,所以它们单独可以。但他们可以同时做一些事情,比如减少可用书籍的数量并订购一些书籍。这两个事件需要按顺序发生,所以我们知道谁拿到了书,而正式的 Java 同步块让我觉得最好的方式是这样做。

但是您最清楚自己要做什么(我对书店将哪种数据放入队列感到有些困惑)。如果它实际上没有回答您的问题,希望这可以为您提供一些信息。

于 2012-08-14T21:08:28.280 回答