Class clazz
有两种方法methodA()
和methodB()
。
如果某些线程在Java
methodB
中(我使用的是Java 8),如何确保methodA
被“阻止”?
通过“阻塞方法B”,我的意思是“等到没有线程在methodA()中”。 (感谢@AndyTurner)
请注意,上面的要求允许以下情况:
methodA
。methodB
中有多个线程,而methodA
中没有线程。methodB
中的主题不会阻止其他主题进入methodA
。 我的试用版:我使用StampedLock lock = new StampedLock
。
methodA
中,请致电long stamp = lock.readLock()
unlockB
并在其中调用lock.unlockRead(stamp)
。methodB
中,拨打long stamp = lock.writeLock()
和lock.unlockWrite(stamp)
。但是,这种锁定策略不允许上述第二种和第三种情况。
编辑:我意识到我没有明确指出methodA
和methodB
之间同步的要求。 @JaroslawPawlak给出的方法适用于当前的要求(我接受它),但不符合我的初衷(也许我应该先澄清它,然后将其发布在另一个帖子中)。
答案 0 :(得分:4)
我认为这可以解决问题:
private final Lock lock = new ReentrantLock();
private final Semaphore semaphore = new Semaphore(1);
private int threadsInA = 0;
public void methodA() {
lock.lock();
threadsInA++;
semaphore.tryAcquire();
lock.unlock();
// your code
lock.lock();
threadsInA--;
if (threadsInA == 0) {
semaphore.release();
}
lock.unlock();
}
public void methodB() throws InterruptedException {
semaphore.acquire();
semaphore.release();
// your code
}
进入methodA
的线程会增加计数并尝试从信号量获取许可证(即如果可用则获得1个许可证,但如果不可用,则仅在没有许可证的情况下继续)。当最后一个线程离开methodA
时,返回许可证。我们不能使用AtomicInteger
,因为更改计数和从信号量获取/释放许可必须是原子的。
进入methodB
的主题需要有一个许可(如果不可用则会等待一个),但是在获得之后,他们立即返回,允许其他人进入methodB
。
修改强>
另一个更简单的版本:
private final int MAX_THREADS = 1_000;
private final Semaphore semaphore = new Semaphore(MAX_THREADS);
public void methodA() throws InterruptedException {
semaphore.acquire();
// your code
semaphore.release();
}
public void methodB() throws InterruptedException {
semaphore.acquire(MAX_THREADS);
semaphore.release(MAX_THREADS);
// your code
}
methodA
中的每个帖子都拥有一个许可证,当该帖子离开methodA
时会被释放。
进入methodB
的线程等到所有1000个许可都可用(即methodA
中没有线程),但不保留它们,这允许其他线程在methodB
时输入这两个方法仍在执行中。
答案 1 :(得分:0)
为什么不使用一种外部协调器? 我的意思是另一个类负责在允许时调用methodA或methodB。 多线程仍然可以通过锁定处理,也可以只使用一些AtomicBoolean(。)。
请在下面找到如何做的天真草稿。
public class MyOrchestrator {
@Autowired
private ClassWithMethods classWithMethods;
private AtomicBoolean aBoolean = = new AtomicBoolean(true);
public Object callTheDesiredMethodIfPossible(Method method, Object... params) {
if(aBoolean.compareAndSet(true, false)) {
return method.invoke(classWithMethods, params);
aBoolean.set(true);
}
if ("methodA".equals(method.getName())) {
return method.invoke(classWithMethods, params);
}
}
}
答案 2 :(得分:0)
你无法真正阻止调用methodA或methodB(而其他线程在其他方法中),但你可以通过这种方式实现线程互通,这样你仍然可以实现你想要的。
class MutualEx {
boolean lock = false;
public synchronized void methodA() {
if (lock) {
try {
wait();
}catch (InterruptedException e) {
}
}
//do some processing
lock = true;
notifyAll();
}
public synchronized void methodB() {
if (!lock) {
try {
wait();
}catch (InterruptedException e) {
}
}
//do some processing
lock = false;
notifyAll();
}
}
现在,为了使这个工作,您创建的任何Thread对象都应该引用MutualEx对象的相同实例。
答案 3 :(得分:0)
简单来说,您需要的是proc c {} {
namespace upvar :: x x y y
expr {$x + $y}
}
。
a
内的线程数。您应该分配ENTER methodB only if no thread inside methodA
来保护变量methodA()
。lock/mutex
。count
。首先进入methodB的线程应检查count++
。
count--
答案 4 :(得分:0)
你需要一个int来计算methodA中的线程,并且一旦在methodA中没有线程,你需要ReentrantLock.Condition来表示在methodB中等待的所有线程:
AtomicInteger threadsInMethodA = new AtomicInteger(0);
Lock threadsForMethodBLock = new ReentrantLock();
Condition signalWaitingThreadsForMethodB = threadsForMethodBLock.newCondition();
public void methodA() {
threadsInMethodA.incrementAndGet();
//do stuff
if (threadsInMethodA.decrementAndGet() == 0) {
try {
threadsForMethodBLock.lock();
signalWaitingThreadsForMethodB.signalAll();
} finally {
threadsForMethodBLock.unlock();
}
}
}
public void methodB() {
try {
threadsForMethodBLock.lock();
while (!Thread.isInterrupted() && threadsInMethodA.get() != 0) {
try {
signalWaitingThreadsForMethodB.await();
} catch (InterruptedException e) {
Thread.interrupt();
throw new RuntimeException("Not sure if you should continue doing stuff in case of interruption");
}
}
signalWaitingThreadsForMethodB.signalAll();
} finally {
threadsForMethodBLock.unlock();
}
//do stuff
}
因此,进入methodB的每个线程将首先检查methodA中是否有人,并发出先前等待线程的信号。另一方面,进入methodA的每个线程将递增计数器以防止新线程在methodB中工作,并且在递减时,如果没有线程留在methodA中,它将释放等待在methodB中执行东西的所有线程。