Java 如何创建一个可以由N个线程执行的线程同步化方法?
我想阻止更多thab 3线程执行方法。该方法可以递归执行。我有以下agly代码。我能用更好的方法做到这一点吗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
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
它应该是完全安全的。您添加了最后一个块,它就解决了一个问题。它应该会起作用。谢谢!