1

我最近正在使用Java Threads并且我正在尝试实现一种能够限制代码块只能由一个线程执行的方法,我们称之为“单线程”。

我已经实现的一个天真的解决方案如下:

if(readFlag())
{
  synchronized(this)
  {
  flag = false;  
  // do some work
  }
} 

在哪里 :

public Boolean synchronized readFlag() {return flag;}

这种幼稚的解决方案仅适用于一个“单个”块,但是当我尝试使用多个“单个”代码块时会出现问题。由于我不能使用相同的标志,因为不同的线程可能会同时输入不同的“单个”代码块。

另一种解决方案可能是为每个“单个”使用一个标志变量数组,但是该解决方案在循环内执行“单个”代码块时会出现问题(或需要使用障碍),而且不是很灵活。

我的问题是:

我如何改进此解决方案以允许执行各种“单个”代码块并允许多次执行相同的单个代码块(例如循环内的单个代码块)。

4

2 回答 2

4

您可以更改同步对象。this除非您需要,否则无需在 上同步。如果您有两个需要同步但可以同时执行的块(每个块只能由一个线程执行),您可以执行类似的操作

private final Object lock1 = new Object();
private final Object lock2 = new Object();
...
synchronized(lock1) { // do stuff. the code in lock2 can be executed while another thread is executing this }
synchronized(lock2) { // do stuff. the code in lock1 can be executed while another thread is executing this }

另请查看ReentrantReadWriteLock以获得更复杂的锁定(以允许多个读取器但只允许一个写入器)。

于 2012-10-30T21:51:29.177 回答
3

在过去的几天里,我遇到了类似的问题。在我的情况下,我必须在 ConcurrentMap 中执行清理任务,并且每 10 分钟只有一个线程应该执行该任务。我不需要同步,因为 ConcurrentMap 迭代器保证不会抛出 ConcurrentModificationException。为了确保只有一个线程会执行清理任务,我使用了 AtomicBoolean:

AtomicBoolean flag = new AtomicBoolean(false);
...

boolean proceed = flag.compareAndSet(false , true);
if(proceed){
   doStuff();
   flag.set(false);
}

所以这避免了在布尔标志上同步。根据要同步的不同代码段,我同意 Jeff 的观点。你可以在不同的对象上同步。

于 2012-10-30T22:20:21.200 回答