简体   繁体   English

两个线程同时访问同一ArrayList?

[英]Two threads accessing the same ArrayList at the same time?

I have the following code in thread 1: 我在线程1中有以下代码:

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

and the following in thread 2: 以及线程2中的以下内容:

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

Now to my question: The currentQueue variable currently has the value of 0. When thread 2 changes the value of currentQueue to 1 and thread 1 waits at line 1 (because of the synchronized), does thread 1 then use the updated currentQueue value in line 2 after thread 2 has finished (that's what I want to). 现在我的问题是:currentQueue变量当前的值为0。当线程2将currentQueue的值更改为1并且线程1在第1行等待(由于已同步)时,线程1会在行中使用更新后的currentQueue值吗?线程2完成后的2(这就是我想要的)。

The correct answer to your question is: The result is undefined. 您问题的正确答案是:结果不确定。

Your monitor object is queues.get(currentQueue), but since currentQueue is variable, your monitor is variable, therefore the state it is currently in is more or less random. 您的监视器对象是queues.get(currentQueue),但是由于currentQueue是可变的,因此您的监视器是可变的,因此它当前处于的状态或多或少是随机的。 Effectively this code would break eventually. 实际上,此代码最终将被破坏。

A simple way to fix it would be a function like this: 一个简单的方法可以解决这个问题:

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

However this is still a bad way of implementing the whole thing. 但是,这仍然是实现整个过程的一种糟糕方法。 You should either try to eliminate the synchronization completely through the use of a concurrent Queue (like ConcurrentLinkedQueue) or work with a lock/final monitor object. 您应该尝试通过使用并发队列(例如ConcurrentLinkedQueue)来完全消除同步,或者使用锁/最终监视器对象。

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

Note that you will have to use that locking every time you access queues or currentQueue as both define the dataset you are using. 请注意,每次访问queuescurrentQueue都定义要使用的数据集时,必须使用该锁定。

The answer to the question is that it depends. 问题的答案在于它取决于。 I assume there is other chunk of code that increments the currentQueue variable. 我假设还有其他代码块可以增加currentQueue变量。 This being the case, the lock is happening not at the ' currentQueue ' variable and neither is it happening at the collection of ' queues ', but rather it is happening on one of the 10 queues (or however many you have) in the ' queues ' collection. 在这种情况下,锁定不会发生在' currentQueue '变量上,也不会发生在' queue '的集合上,而是发生在'10个队列中的10个(或者有很多)队列中的一个上。 队列收集。

Hence, if both threads happen to access the same queue (say queue 5), then the answer to your question is yes. 因此,如果两个线程碰巧都访问同一个队列(例如队列5),那么您问题的答案是肯定的。 However, for that to happen is one in ten chance (one in x chance, where x = the number or queues in the ' queues ' collection). 但是,发生这种情况的机会是十分之一(x机会是1,x =“ queues ”集合中的队列数 )。 Therefore, if the threads access different queues, then the answer is no. 因此,如果线程访问不同的队列,那么答案是否定的。

Assuming you have no other thread will change the value of currentQueue, yes Thread 1 will end up using the queue pointed to by the updated value of currentQueue , since you're invoking queues.get(currentQueue) once again in the body of the synchronized block. 假设您没有其他线程会更改currentQueue的值,那么是的,线程1最终将使用currentcurrent的更新值指向的队列结束,因为您在同步的正文中再次调用了queues.get(currentQueue)块。 This however doesn't mean that your synchronization is sound. 但是,这并不意味着您的同步是正确的。 You actually should synchronize on currentQueue, since it seems to be the shared key to access the current queue. 实际上,您应该在currentQueue上进行同步,因为它似乎是访问当前队列的共享密钥。

Also remember when you use synchronize you're synchronizing on the reference of the variable, and not its value. 还要记住,当您使用sync时,您是在变量的引用而不是其值上进行同步。 So if you reassign a new object to it, your synchronization doesn't make sense anymore. 因此,如果将新对象重新分配给它,则同步不再有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM