Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何创建一个可以由N个线程执行的线程同步化方法?_Java - Fatal编程技术网

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

Java 如何创建一个可以由N个线程执行的线程同步化方法?,java,Java,我想阻止更多thab 3线程执行方法。该方法可以递归执行。我有以下agly代码。我能用更好的方法做到这一点吗 private static class MyHolder { private static Semaphore limitThreadsSemaphore = new Semaphore(3); private static Set<Thread> asquiredThreads = new HashSet<Thread>(); } @Over

我想阻止更多thab 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();
}
私有静态类MyHolder{
私有静态信号量limitThreadsSemaphore=新信号量(3);
私有静态集asquiredThreads=newhashset();
}
@凌驾
公共方法(){
如果(!MyHolder.asquiredThreads.contains(Thread.currentThread())){
已同步(MyHolder.asquiredThreads){
如果(!MyHolder.asquiredThreads.contains(Thread.currentThread())){
试一试{
MyHolder.limitThreadsSemaphore.acquire();
MyHolder.asquiredThreads.add(Thread.currentThread());
}最后{
MyHolder.limitThreadsSemaphore.release();
MyHolder.asquiredThreads.remove(Thread.currentThread());
}
}
}
}
返回super.someMethod();
}
谢谢。

我想“someMethod”是您想要阻止执行的方法,是吗?。你为什么不这样做

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;
    }
}

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

private static Semaphore limitThreadsSemaphore = new Semaphore(3);
@Override
public void someMethod() {
     limitThreadsSemaphore.acquire();
      // do work.
     limitThreadsSemaphore.release();
}
更新:如果需要在线程内递归调用方法,那么最简单的方法是使用helper方法获取信号量,然后在获取sempahor后从该helper方法调用递归方法。您将在所有初始调用中调用helper而不是原始方法

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

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

如果这不是一个选项,那么我能想到的最简单的方法就是使用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();
    }
  }
}
ThreadLocal alreadyIn=new ThreadLocal();
公共方法(){
布尔值needSem=(alreadyIn.get()==null);
如果(需要扫描电镜){
semaphore.acquire();
set(新对象());
}
试一试{
//做事
}最后{
如果(需要扫描电镜){
alreadyIn.remove();
semaphore.release();
}
}
}

因为此方法可以递归执行。在这种情况下,我不需要块。现在尝试编辑的代码,您不会说需要进行递归调用。抱歉,问题已编辑。我不相信你的解决办法。方法应该同时在3个线程中工作,第4个线程应该被阻塞。但您的解决方案不限制线程数。第一个线程将信号量required设置为true,并且工作时间很长。此代码不会阻止所有其他线程。如果我对SemaphoreQuired使用ThreadLocal,您的解决方案就会起作用。SemaphoreQuired变量不是线程共享的,不是静态的。如果需要,可以将此变量放入线程局部变量中。局部变量由Java中的线程共享。新编辑的代码将无法编译。不适用于递归调用。如果使用同步块,线程不会被阻塞,但一个线程的信号量获取2次。@user3153317,请更新您的问题以提及此要求。我不能使用其他方法调用。只有在someMethod()中使用了此调用的某些逻辑。@user3153317,才可以对其重新排序。将信号量放入
someMethod()
中,并在
helper()
中执行真正的工作。通过这种方式,您不会将API更改为外部世界的API,但您在内部满足了您的需求。我不能这样做,因为我有一个巨大的逻辑,这个方法再次递归地涉及。我没有从这个类中调用它。@MaratKamalov以什么方式?ThreadLocal的要点是它是线程本地的-此线程的
alreadyIn
值不受任何其他线程的影响,因此不存在争用条件。只要
someMethod
之外没有任何内容触及
alreadyIn
它应该是完全安全的。您添加了最后一个块,它就解决了一个问题。它应该会起作用。谢谢!