如何创建一个线程同步一个可以由N个线程执行的方法?

时间:2014-07-11 07:41:28

标签: java

我想阻止来自更多3个线程的方法执行。该方法可以递归地执行。我有以下agly代码。我可以通过更好的方式实现这个目标吗?

private static class MyHolder {
    private static Semaphore limitThreadsSemaphore = new Semaphore(3);
    private static Set<Thread> asquiredThreads = new HashSet<Thread>();
}

@Override
public void someMethod() {
    if (!MyHolder.asquiredThreads.contains(Thread.currentThread())) {
        synchronized (MyHolder.asquiredThreads) {
           if (!MyHolder.asquiredThreads.contains(Thread.currentThread())) {
               try {
                   MyHolder.limitThreadsSemaphore.acquire();
                   MyHolder.asquiredThreads.add(Thread.currentThread());
               } finally {
                   MyHolder.limitThreadsSemaphore.release();
                   MyHolder.asquiredThreads.remove(Thread.currentThread());
               }
           }
        }
    }
    return super.someMethod();
}

感谢。

3 个答案:

答案 0 :(得分:0)

我想&#34; someMethod&#34;是你要阻止执行的方法,是吗?你为什么不这样做? :

private static class MyHolder {
    private static Semaphore limitThreadsSemaphore = new Semaphore(3);

    public boolean semaphoreAdquired = false; //Make it private

    public Semaphore getSemaphore()
    {
        return limitThreadsSemaphore;
    }
}



@Override
public void someMethod() {

    boolean ReleaseSemaphore = false;

    if(!semaphoreAdquired)
    {
        MyHolder.getSemaphore().acquire();
        semaphoreAdquired = true;
        ReleaseSemaphore = true;
    }
    super.someMethod();
    if(ReleaseSemaphore)
    {
        MyHolder.getSemaphore().release();
        semaphoreAdquired = false;
    }
}

答案 1 :(得分:0)

根据Semaphor的文档,这应该只能在关键部分使用 acquire()release()来实现。此外,您应该能够将信号量放在当前类中,不需要单独的类来包含Semaphor。

private static Semaphore limitThreadsSemaphore = new Semaphore(3);
@Override
public void someMethod() {
     limitThreadsSemaphore.acquire();
      // do work.
     limitThreadsSemaphore.release();
}

更新:如果需要在线程内递归调用方法,那么最简单的方法是使用辅助方法获取信号,然后从该辅助方法调用递归方法获得sempahor。在所有初始调用中,您将调用助手而不是原始方法。

private static Semaphore limitThreadsSemaphore = new Semaphore(3);
public void someMethodHelper() {
     limitThreadsSemaphore.acquire();
     someMethod();
     limitThreadsSemaphore.release();
}
@Override
public void someMethod() {
  // do work, with recursive calls.
}

答案 2 :(得分:0)

最简单的方法是将递归方法重构为私有,然后让公共方法无条件地获取信号量,调用私有方法然后再次释放信号量。递归调用直接路由到私有方法,因此不要通过信号量保护代码。

如果那不是一个选项,那么我能想到的最简单的方法就是使用ThreadLocal标志

ThreadLocal<Object> alreadyIn = new ThreadLocal<>();
public void someMethod() {
  boolean needSem = (alreadyIn.get() == null);
  if(needSem) {
    semaphore.acquire();
    alreadyIn.set(new Object());
  }
  try {
    // do stuff
  } finally {
    if(needSem) {
      alreadyIn.remove();
      semaphore.release();
    }
  }
}