【问题标题】:Two threads accessing the same ArrayList at the same time?两个线程同时访问同一个 ArrayList?
【发布时间】:2013-10-20 16:20:40
【问题描述】:

我在线程 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 行中的值(这就是我想要的)。

【问题讨论】:

  • 你在本地范围内改变它。
  • 您的同步错误。从您的代码中,访问队列的关键(并且您碰巧有很多)似乎是索引:currentQueue。这就是您应该规范访问(并最终同步)的内容,尤其是当它以读/写方式访问时。
  • 当然是的,因为线程二先拿到锁并操作数据,所以线程二解锁,线程一获取锁后,就有线程二修改的数据了。

标签: java multithreading arraylist synchronized


【解决方案1】:

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

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

【讨论】:

    【解决方案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);
    }
    

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-09
        • 1970-01-01
        • 2016-08-15
        • 2021-12-06
        • 1970-01-01
        相关资源
        最近更新 更多