I have two methods: a() and b(). While I'm fine with multiple threads accessing any of the methods at the same time (that is desirable), I do not want any threads to enter a() while b() is being executed.
How do I do that?
Edit 1
Lets say there are 4 threads and Thread 1 is accessing A(). What I want is all of the 4 threads should not use B().
CHECK UPDATE at the bottom - I don't think this approach can work. Leaving it for information.
You could use a Semaphore:
- if a thread is in
b(), a thread trying to executea()will block until the execution ofb()is over. - if a thread is in
b()and a second thread tries to runb()it will be able to - if 2 threads execute
a()whileb()is not being executed both will run
Note: once a thread is in a() and has passed the "semaphore test", another thread can start running b() before the end of a()
The principle should work but I have not tested it.
private final Semaphore inB = new Semaphore(1);
public void a() throws InterruptedException {
inB.acquire(); //blocks until no thread is in b any longer
//now we are good to go and execute a()
//release the semaphore immediately for other threads who want to run a()
inB.release();
//rest of your code here
}
public void b() {
//does not block to allow 2 thread running b() simultaneously
boolean needToRelease = inB.tryAcquire();
//rest of your code
//if the permit was acquired, release it to allow threads to run a()
if (needToRelease) {
inB.release();
}
}
EDIT
Your intention is not clear and your question has been edited because one of your comments says that you want a() and b() to be mutually exclusive (many threads can run either a() or b() in parallel, but a() and b() should never be run in parallel). In that case, you can use the same logic with 2 semaphores inA and inB.
UPDATE => BUG
As pointed out by @yshavit in a comment to another answer, there is a race condition in the code in the following scenario:
- T1 runs
a()and acquiresinB - T2 runs
b()and fails to acquireinB - T1 releases
inB - T3 runs
a()and manages to acquireinBalthough T2 is runningb()
It seems that this can't be achieved with Sempahores only. This answer gives a better solution.
Exception handling ommitted for simplicity:
public class Test {
private final Object lock = new Object();
private int counterA;
private int counterB;
public void a() {
synchronized(lock) {
while(counterB > 0) {
lock.wait();
}
++counterA;
}
// do work
synchronized(lock) {
--counterA;
lock.notifyAll();
}
}
public void b() {
synchronized(lock) {
while(counterA > 0) {
lock.wait();
}
++counterB;
}
// do work
synchronized(lock) {
--counterB;
lock.notifyAll();
}
}
}
java.util.concurrent.locks is a Java package which contains several locks
in a(), take a lock and release it at the end of a()
in b(), do the same with the same lock
If you want to deal with asymmetric behavior you may use a ReadWriteLock, a() is reader and b() is writer : several b() locks but several a() doesn't.
来源:https://stackoverflow.com/questions/13320713/mutually-exclusive-method-execution-in-java