Semaphore:
public void enter() throws InterruptedException {
synchronized (block) {
++current;
if (current > permits) {
try {
block.wait();
} catch (InterruptedException e) {
throw e;
}
}
}
}
public void realese() {
synchronized (block) {
--current;
block.notify();
}
}
How to make a queue in the semaphore? I want threads to be executed in the order of calling the enter().
Here's one way:
Have the release() method wake up every waiting thread (i.e., block.notifyAll())
In the enter() method, have each waiting thread look at the head of the queue.
If the thread at the head of the queue is the current thread, pop the queue and complete the enter() call, -OR-
Go back to waiting otherwise.
But there's a subtle problem that I'll leave to you to work out how to fix:
If thread A wakes up, finds itself at the head of the queue, pops the queue and returns,
Then, thread B could wakes up, finds its self at the head of the queue, and it also pops the queue and returns.
And there you have one release() call which just allowed two threads to enter().
That would be bad. So, you'll need to figure out a way to guarantee that no more than one thread can complete the enter() call each time release() is called.
If your using a newer java you can just add a fairness setting to the constructor.
Semaphore(int permits, boolean fair)
like this
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
Related
I am writing a class called MyReentrantLock and I have to create a function called acquire() that locks a thread if it's not locked and if it is indeed locked then it has to wait until it unlocks to lock it again. It's kind of confusing and I can't use wait() or sleep(), only AtomicBoolean and Thread class in java.
public class MyReentrantLock implements Lock{
AtomicBoolean locked = new AtomicBoolean(false);
long IdOfThreadCurrentlyHoldingLock;
#Override
public void acquire() {
if(!locked.compareAndSet(false,true)){
WHAT DO I WRITE HERE!!
}
locked.compareAndSet(false, true);
IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
}
#Override
public boolean tryAcquire() {
if(!locked.compareAndSet(false,true))
return false;
else {
acquire();
return true;
}
}
#Override
public void release() {
locked.compareAndSet(true,false);
if(!locked.compareAndSet(true,false) || IdOfThreadCurrentlyHoldingLock!=Thread.currentThread().getId()){
throw new IllegalReleaseAttempt();
}
}
Replace your if with a while. You may keep the body empty, even though it might be advisable to sleep some milliseconds.
The reason is: Your method acquire neither throws an exception nor does it return a result (success/failure). Thus the calling code would assume when the call to acquire is done, the thread can continue doing the sensitive job.
So you cannot exit the method without having the lock, even if that means to wait indefinitely. A more advanced method would allow to define a timeout but then also needs to communicate whether the lock is aquired or the timeout was reached.
I'm trying to resolve a university exercise. The class AImpl has a method ma(B b) that creates and runs two threads. These threads have to call mb1() and mb2() (they are simple methods that just print a text, so I didn't include them). The calling thread should then wait for mb1() to terminate before finishing.
My logic is:
The first thread enters and after finishing the execution of b.mb1() starts to wait() on the current object, releasing the mutex. Then the second thread runs and it does the same. When they are both waiting, the calling thread calls notifyAll() on the object, waking both of them. They execute b.mb2() and then terminate.
The problem is that when the first thread starts waiting with object.wait(), the control flow doesn't return on the calling thread and the program enters in a deadlock.
Where is my logic flawed?
public class AImpl{
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
BImpl b = new BImpl();
AImpl.ma(b);
}
public static void ma(B b) throws InterruptedException {
Thread thread = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
Thread thread1 = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
thread.run();
thread1.run();
synchronized(object){
object.notifyAll();
}
System.out.println("Program finished.");
}
}
The notify/notifyAll methods tell the scheduler to notify one/all of the threads currently waiting on the lock that notify or notifyAll was called on. But if a thread hasn't started waiting yet then it doesn't get notified.
The solution is to introduce a condition variable that keeps wait from being called if the notifying has happened already. Define it in the same scope as your lock:
public static volatile boolean ready = false;
Then use it to guard the wait block, like this:
while (!ready) {
object.wait();
}
The code calling notify/notifyAll needs to set the variable (it doesn't matter what order you do it in because the notification doesn't happen until the lock is released):
synchronized (object) {
ready = true;
object.notifyAll();
}
What happens:
If the waiting thread gets to the waiting part before the notifying thread does its notifying, then the waiting thread finds ready is false, so it enters the wait method, releases the lock, and stays there. Then the notifying thread changes the flag to true and wakes up the waiting thread, which can leave the wait, reacquire the lock, and then leave the loop now that the flag is set.
But if the notifying thread does its notify before the other thread waits, that's ok, because the ready flag now prevents the thread from entering the wait, it can skip over it.
Further reading: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
I have many threads which monitor a certain state. If the application gets into that state, then I need to do some extra work. I want to allow just 1 thread to execute that and want to block the others until that work is finished. Blocking mean, that they must not execute that task again.
I have the following scenario:
ReentrantLock lock = new ReentrantLock
void doSomething() {
if (lock.tryLock()) {
try {
doSomeWork()
} finally {
lock.unLock()
}
} else {
// wait for DoSomeWork is done
}
}
I can monitor lock.isLocked() in a loop, but actually I just want to have some sort of wait until the work is finished by the other thread.
According to documentation about ReentrantLock class:
It is recommended practice to always immediately follow a call to
lock with a try block, most typically in a before/after construction
such as:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
From the documentation for lock() method:"If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired" and this is what you want to be guaranteed in your scenario.
public class MyLockConditionTest {
private final Lock alock = new ReentrantLock();
private final Condition condition = alock.newCondition();
private String message = null;
public void waitForCallback() {
alock.lock();
try {
// wait for callback from a remote server
condition.await();
doSomething(message);
} finally {
alock.unlock();
}
}
// another thread will call this method as a callback to wake up the thread called condition.await()
public void onCallbackReceived(String message) {
alock.lock();
try {
this.message = message
condition.signal();
} finally {
alock.unlock();
}
}
}
I have this code using ReentrantLock and Condition to implement a class to wait on certain callbacks from a remote server. I tested this code and seems working but I have a few questions.
Why do I need to do alock.lock() / unlock() in onCallbackReceived(). Without calling lock() / unlock(), I was getting an IllegalState exception. I am confused because the lock is held by the caller of waitForCallback() when onCallbackReceived() invoked by another thread so alock.lock() in onCallbackReceived() will always fail.
Do I need to wrap condition.await() in waitForCallback() with while loop?
while(message==null)
condition.await();
Why do I need to do alock.lock() / unlock() in onCallbackReceived(). Without calling lock() / unlock(), I was getting an IllegalState exception.
You are trying to signal a condition in which you do not own the lock. The only way you would hold the lock is if onCallbackReceived is called from doSomething which there is no indication that is occurring.
Do I need to wrap condition.await() in waitForCallback() with while loop?
Yes, imagine you have 5 threads stopped on the condition and 5 threads blocked on lock. Only one thread can wake up. What if when a waiting thread finally wakes up another thread had null'd that field out? You will need to check again to ensure the predicate is still true.
I have three classes, one that is meant to represent a pile of urls
private Queue<String> queue = new LinkedList<String>();
public Queue<String> getQueue() {
return queue;
}
private int limit = 5;
private int stillParsing;
public synchronized String getNextString() throws InterruptedException {
while (queue.isEmpty()||stillParsing > limit) {
System.out.println("no for you "+ queue.peek());
wait();
}
System.out.println("grabbed");
notify();
stillParsing++;
System.out.println(queue.peek());
return queue.remove();
}
public synchronized void doneParsing() {
stillParsing--;
}
}
A thread class whose run method is
public void run(){
try {
sleep(30);
for(;;){
String currenturl = pile.getNextString();
//(do things)
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
pile.doneParsing();
}
}
And a mapper that actually adds objects into the pile of urls using this snipet
while (urls.hasMoreTokens()) {
try{
word.set(urls.nextToken());
String currenturl = word.toString();
System.out.println(currenturl);
pile.getQueue().add(currenturl);
From debugging what I think happens is that all of the threads try to get from the queue at once before the mapper has a chance to populate it and they get stuck waiting. Unfortunately all of the threads waiting is causing my program to hang up and not add more urls to the queue. How should I go about taking care of this issue? Preferably while still using wait notify.
while (urls.hasMoreTokens()) {
try {
word.set(urls.nextToken());
String currenturl = word.toString();
System.out.println(currenturl);
pile.getQueue().add(currenturl);
In the above code, you're breaking the encapsulation of the pile by adding something to its queue without going though a method of the pile. You should not have a getQueue() method in this class: all the accesses to this shared data structure should be synchronized on the same lock. You should thus add a synchronized method allowing to add a URL to the queue. And this method should also call notify() (or better: notifyAll()), in order to wake up the threads that are waiting for some element to be in the queue:
public synchronized void addUrl(String url) {
queue.add(url);
notifyAll();
}
Even without reading all lines of your code and explanations I can say that your usage of wait and notify are buggy.
Method wait() is blocking. It exits only when notify() on the same monitor is called. This means that you cannot put both wait() and notify() from the same thread. You simply never arrive to notify() because wait() is blocked forever.
Other version of wait(): wait(timeout) is blocked but is limited by specified timeout.
Moreover wait/notify pair work only if they are written into synchronized block:
// thread-1
synchronoized(obj) {
obj.wait();
}
// thread-2
synchronoized(obj) {
obj.notify();
}
Thread-1 will exit wait when thread-2 calls notify.