2

我在线程 1 中有以下代码:

synchronized (queues.get(currentQueue)) {            //line 1
   queues.get(currentQueue).add(networkEvent);       //line 2
}

以及线程2中的以下内容:

synchronized (queues.get(currentQueue)) {
   if (queues.get(currentQueue).size() > 10) {
      currentQueue = 1;
   }
}

现在我的问题是:currentQueue 变量当前的值为 0。当线程 2 将 currentQueue 的值更改为 1 并且线程 1 在第 1 行等待(因为同步)时,线程 1 是否会在行中使用更新后的 currentQueue 值2 在线程 2 完成后(这就是我想要的)。

4

3 回答 3

2

您的问题的正确答案是:结果未定义。

您的监视器对象是 queues.get(currentQueue),但由于 currentQueue 是可变的,因此您的监视器是可变的,因此它当前所处的状态或多或少是随机的。实际上,此代码最终会中断。

修复它的一个简单方法是这样的函数:

protected synchronized QueueType getCurrentQueue() {
  return queues.get(currentQueue);
}

然而,这仍然是实现整个事情的糟糕方式。您应该尝试通过使用并发队列(如 ConcurrentLinkedQueue)来完全消除同步,或者使用锁定/最终监视器对象。

final Object queueLock = new Object();
...
synchronized(queueLock) {
  queues.get(currentQueue).add(networkEvent);
}

请注意,您每次访问时都必须使用该锁定,queues或者currentQueue两者都定义您正在使用的数据集。

于 2013-10-12T18:31:07.573 回答
2

这个问题的答案是视情况而定。我假设还有其他代码块会增加 currentQueue 变量。在这种情况下,锁定不是发生在“ currentQueue ”变量中,也不是发生在“队列”的集合中,而是发生在“队列”中的 10 个队列之一(或者你有多少队列)上队列的集合。

因此,如果两个线程碰巧访问同一个队列(比如队列 5),那么您的问题的答案是肯定的。但是,发生这种情况的几率是十分之一(x 几率中的一个,其中 x = ' queues ' 集合中的数量或队列)。因此,如果线程访问不同的队列,那么答案是否定的。

于 2013-10-12T18:36:08.407 回答
1

假设您没有其他线程会更改 currentQueue 的值,是的,线程 1 最终将使用currentQueue的更新值指向的队列,因为您在同步的主体中再次调用 queues.get(currentQueue)堵塞。然而,这并不意味着您的同步是正确的。您实际上应该在 currentQueue 上进行同步,因为它似乎是访问当前队列的共享密钥。

还要记住,当您使用 synchronize 时,您正在同步变量的引用,而不是它的值。因此,如果您为它重新分配一个新对象,那么您的同步就不再有意义了。

于 2013-10-12T18:33:36.747 回答