读取数组的锁定

时间:2012-08-13 19:52:44

标签: java concurrency multidimensional-array thread-safety scalability

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

考虑一本名为" 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。同样,第[4] [5]行表明,Bookstore2售价为70美元,愿意出售2份。

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

&#34; BookA&#34; ----&GT; INT [] []

&#34; bookN的&#34; ----&GT; INT [] []

来自Bookstore1和Bokstore2的数据到达两个独立的线程。目前,我将原始数据对象存储在阻塞队列中,并使用单个线程(&#34; ProcessingThread&#34;)来创建和修改(如果有更新)上述数组。

enter image description here

最后,我有一些客户,他们在一个单独的帖子中(&#34; CustomerThread&#34;)向我发送购买/出售书籍的订单。

典型的订单如下:&#34;以50美元购买BookA的3&#34;:

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

1)检查地图是否包含密钥&#34; BookA&#34;。

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

3)然后我迭代克隆的数据以找到价格和总数量。

我的问题是:

a)有人可以确认我不需要同步生产者(&#34; ProcessingThread&#34;)。由于dataStorage(int [] [])仅由&#34; ProcessingThread&#34;线。此外,由于dataStorage是易变的,因此&#34;发生之前&#34;将在我写信时建立(因此,&#34; CustomerThread&#34;将看到最新更新的数据)。

b)是否有更好的(比使用锁定更具可扩展性)方式来确保&#34; CustomerThread&#34 ;?中的线程安全性?我可以通过使用AtomicIntegerArray逃脱吗?

由于

1 个答案:

答案 0 :(得分:1)

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

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

另一种解决方案是替换整个数组而不是修改它们。数组变得有效不可变。从一组数据到下一组数据的变化是即时的,并且数据始终是一致的。现在,数组引用是易失性的这一事实确保了CustomerThread立即可见的更改,现在永远不必等待锁定。

我喜欢第二种解决方案,它更像是回答你的问题B.(原子药往往价格昂贵。如果你可以用一个原子替换一个锁,你就会领先于游戏,但如果你要替换一个用100个原子锁定,甚至只用10个,你就在后面。)

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

但是你最了解你要做的事情(我对书店放入队列的数据有点困惑)。希望如果它实际上没有回答你的问题,这会给你一些信息。