I am trying to implement Reentrant locks on multi-threads but for some reason, the same thread unlocks and then locks again resulting in always the same thread to run therefore the same operation.
Below is the code how the threads are spawn
IntStream.range(0,(NUMBER_OF_THREADS)).forEach(index ->{
boolean operation = (index % 2 == 0) ? true : false;
Thread t = new Thread(new Client(operation,this));
t.start();
});
and here is how the run function of the thread works
#Override
public void run() {
while(!Thread.interrupted()) {
System.out.println("Trying to acquire lock : " + main.getLock().tryLock()
+ " thread id " + Thread.currentThread().getName());
// if (main.getLock().tryLock()) {
try {
main.getLock().lock();
if(main.getLock().isHeldByCurrentThread()) {
System.out.println("Lock held by this thread " + main.getLock().isHeldByCurrentThread()
+ " thread id : " + Thread.currentThread().getName());
if (operation) {
main.getcAaccount().deposit(1);
} else {
main.getcAaccount().withdraw(2);
}
Thread.currentThread().sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Thread id : " + Thread.currentThread().getName() + " unlocking");
main.getLock().unlock();//always have the unlock part here to ensure it unlock
}
}
It correctly prints that the other 5 threads are trying to acquire the lock and failing and then Thread id...is unlocking...and immediately the same thread locks again even though it should be sleeping.
Have I missed anything in this logic scenario?
Thank you in advance.
EDIT Screenshot of the suggested fix.
Reentrancy requires each lock to be followed by a subsequent unlock. For example, if I invoke lock.lock() three times, it's expected that I also invoke lock.unlock() three times. The ReentrantLock will not consider itself unlocked until this sequence of events occurs.
What you don't realize is that lock.tryLock(), if successful, will act essentially like invoking lock.lock(). So by locking twice, you need to also unlock twice. In your code example, you are unlocking only once and so the thread that initially locked still technically owns the lock.
Fixing it should be simple, you can remove the second lock.lock() from your code and the mutual exclusion should still hold. Either that, or if you need blocking on lock, then replace lock.tryLock() with lock.lock().
Based on your edit, you fixed one issue with removing the extra lock, but now you are running into a timing issue. You don't really need the tryLock. You can replace it with lock since a lock invocation will suspend the thread and block if the lock is already being held (eventually waking up when an unlock is invoked).
Related
I know that the synchronize(LOCK) is unfair, which means there is no guarantee that the longest waiting thread will win the lock. However in my little experiment below it seems that the lock was acquired by shortest waiting threads...
public class Demo {
public static final Object LOCK = new Object();
public void unfairDemo(){
// Occupy the lock for 2 sec
new Thread(() -> {
synchronized (LOCK) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// Spawn 10 new threads, each with 100ms interval, to see which can win the lock
// If lock is fair then it should print the i in asc order
for (var i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
System.out.println("Added " + String.valueOf(finalI) + "th element to wait for lock");
synchronized (LOCK) {
System.out.println("I got the lock, says " + String.valueOf(finalI) + "-th thread");
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
// Keep the program alive
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Running unfairDemo() prints the following:
Added 0th element to wait for lock
Added 1th element to wait for lock
Added 2th element to wait for lock
Added 3th element to wait for lock
Added 4th element to wait for lock
Added 5th element to wait for lock
Added 6th element to wait for lock
Added 7th element to wait for lock
Added 8th element to wait for lock
Added 9th element to wait for lock
I got the lock, says 9-th thread
I got the lock, says 8-th thread
I got the lock, says 7-th thread
I got the lock, says 6-th thread
I got the lock, says 5-th thread
I got the lock, says 4-th thread
I got the lock, says 3-th thread
I got the lock, says 2-th thread
I got the lock, says 1-th thread
I got the lock, says 0-th thread
I expected that the order would be scrambled, but no matter how I tried the results are in reverse order. What did I do wrong here?
There are many sources, such as this, that already indicate that there should be no assumption regarding the order in which threads acquire locks. But it doesn't mean the order has to be scrambled.
It probably depends at the very least on the JVM implementation. For example, this document about HotSpot says:
Contended synchronization operations use advanced adaptive spinning techniques to improve throughput even for applications with significant amounts of lock contention. As a result, synchronization performance becomes so fast that it is not a significant performance issue for the vast majority of real-world programs.
...
In the normal case when there's no contention, the synchronization operation will be completed entirely in the fast-path. If, however, we need to block or wake a thread (in monitorenter or monitorexit, respectively), the fast-path code will call into the slow-path. The slow-path implementation is in native C++ code while the fast-path is emitted by the JITs.
I'm not an expert on HotSpot (maybe someone else can provide a more authoritative answer), but based on the C++ code, it looks like the contending threads will be pushed onto a LIFO structure, which may explain the stack-like order you observed:
// * Contending threads "push" themselves onto the cxq with CAS
// and then spin/park.
...
// Cxq points to the set of Recently Arrived Threads attempting entry.
// Because we push threads onto _cxq with CAS, the RATs must take the form of
// a singly-linked LIFO.
What did I do wrong here?
You do all right.
Your expirement shows program execution order in this particular case. Java do not guarantee any order of threads execution without special efforts from programmer's side.
Try this to see chaos:
public class Demo {
public static final Object LOCK = new Object();
public void unfairDemo() {
createThread(0).start();
for (var i = 1; i < 5; i++) {
createThread(i).start();
}
}
private static Thread createThread(final int number) {
return new Thread(() -> {
System.out.println("Added " + number + "th element to wait for lock");
synchronized (LOCK) {
System.out.println("I got the lock, says " + number + "-th thread");
try {
Thread.sleep(number == 0 ? 2000 : 100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
});
}
public static void main(String[] args) {
new Demo().unfairDemo();
}
}
I have the following synchronized method which is used to shut down the task manager. The logic is to check for active tasks and if there is any, I will wait for 1 second and will check again.
But it seems like find bugs plugin is not allowing me to use Thread.sleep() inside a synchronized block and giving the following warning
Method calls Thread.sleep() with a lock held
This method calls Thread.sleep() with a lock held. This may result in very poor performance and scalability, or a deadlock, since other threads may be waiting to acquire the lock. It is a much better idea to call wait() on the lock, which releases the lock and allows other threads to run.
Any idea on how to overcome this issue ?
public synchronized void stop() {
// try to wait a bit for task shutdown
for (int i = 0; i < 5; i++) {
if (activeTaskCount == 0) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
}
if (activeTaskCount > 0) {
log.warn("Unable to shutdown all polling tasks of " + jmsConsumerName);
}
if (JMSTaskManagerState != STATE_FAILURE) {
JMSTaskManagerState = STATE_STOPPED;
}
log.info("Task manager for jms consumer " + receiveTimeout + " shutdown");
}
all. I have a question for Java wait-notify mechanism. The answer is is there a guaranty that the threads will be executed in this order - from last to the first etc. the result always will be 100, 99, ... , 1 ? This is the snippet of code:
public class Main {
static int counter = 0;
static Object o = new Object();
public static void main(String[] args){
for(int i = 0; i < 100; ++i){
new Thread(() -> {
synchronized (o) {
try {
int c = ++counter;
o.wait();
System.out.println("" + c);
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o) {
new Thread(()-> {
synchronized(o){
System.out.println("LAsttttttttttttttttt");
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
o.notifyAll();
}
}
}
I run it 10 times and the result is always the same. I coudn't find anything about this in internet. And one more question - when we have 100 threads waiting, when we notifyAll, is there a guaranty that first one of waiting threads will be executed, after then a second one and after all 100 waiting threads are executed, other waiting methods(which were in synchronized block, but don't have wait() in their body), will be executed after that (after all 100 threads that were waiting are executed). Or notifyAll only guaranty that all waiting threads will start fighting with every method which is synchronized by this object? I thing that this is the answer :
"The awakened threads will not be able to proceed until the current
* thread relinquishes the lock on this object. The awakened threads
* will compete in the usual manner with any other threads that might
* be actively competing to synchronize on this object; for example,
* the awakened threads enjoy no reliable privilege or disadvantage in
* being the next thread to lock this object."
But I want to be sure that I understand what's going on when we have wait-notify.
Thanks in advance.
No . .there is no guarantee that a set of awoken threads will be executed in any particular order. (This may happen in order because of a particular implementation of JVM or the speed of the computer the program is run on, or many other load based variables. However, there is no language guarantee.)
Java's synchronized code block makes no guarantee about the sequence in which threads waiting to enter the synchronized block are allowed to enter, and notifyAll() doesn't present itself as a special case.
As you have seen in notifyAll() javadoc (emphasis mine):
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
I was trying to implement something similar to Java's bounded BlockingQueue interface using Java synchronization "primitives" (synchronized, wait(), notify()) when I stumbled upon some behavior I don't understand.
I create a queue capable of storing 1 element, create two threads that wait to fetch a value from the queue, start them, then try to put two values into the queue in a synchronized block in the main thread. Most of the time it works, but sometimes the two threads waiting for a value start seemingly waking up each other and not letting the main thread enter the synchronized block.
Here's my (simplified) code:
import java.util.LinkedList;
import java.util.Queue;
public class LivelockDemo {
private static final int MANY_RUNS = 10000;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < MANY_RUNS; i++) { // to increase the probability
final MyBoundedBlockingQueue ctr = new MyBoundedBlockingQueue(1);
Thread t1 = createObserver(ctr, i + ":1");
Thread t2 = createObserver(ctr, i + ":2");
t1.start();
t2.start();
System.out.println(i + ":0 ready to enter synchronized block");
synchronized (ctr) {
System.out.println(i + ":0 entered synchronized block");
ctr.addWhenHasSpace("hello");
ctr.addWhenHasSpace("world");
}
t1.join();
t2.join();
System.out.println();
}
}
public static class MyBoundedBlockingQueue {
private Queue<Object> lst = new LinkedList<Object>();;
private int limit;
private MyBoundedBlockingQueue(int limit) {
this.limit = limit;
}
public synchronized void addWhenHasSpace(Object obj) throws InterruptedException {
boolean printed = false;
while (lst.size() >= limit) {
printed = __heartbeat(':', printed);
notify();
wait();
}
lst.offer(obj);
notify();
}
// waits until something has been set and then returns it
public synchronized Object getWhenNotEmpty() throws InterruptedException {
boolean printed = false;
while (lst.isEmpty()) {
printed = __heartbeat('.', printed); // show progress
notify();
wait();
}
Object result = lst.poll();
notify();
return result;
}
// just to show progress of waiting threads in a reasonable manner
private static boolean __heartbeat(char c, boolean printed) {
long now = System.currentTimeMillis();
if (now % 1000 == 0) {
System.out.print(c);
printed = true;
} else if (printed) {
System.out.println();
printed = false;
}
return printed;
}
}
private static Thread createObserver(final MyBoundedBlockingQueue ctr,
final String name) {
return new Thread(new Runnable() {
#Override
public void run() {
try {
System.out.println(name + ": saw " + ctr.getWhenNotEmpty());
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
}
}, name);
}
}
Here's what I see when it "blocks":
(skipped a lot)
85:0 ready to enter synchronized block
85:0 entered synchronized block
85:2: saw hello
85:1: saw world
86:0 ready to enter synchronized block
86:0 entered synchronized block
86:2: saw hello
86:1: saw world
87:0 ready to enter synchronized block
............................................
..........................................................................
..................................................................................
(goes "forever")
However, if I change the notify() calls inside the while(...) loops of addWhenHasSpace and getWhenNotEmpty methods to notifyAll(), it "always" passes.
My question is this: why does the behavior vary between notify() and notifyAll() methods in this case, and also why is the behavior of notify() the way it is?
I would expect both methods to behave in the same way in this case (two threads WAITING, one BLOCKED), because:
it seems to me that in this case notifyAll() would only wake up the other thread, same as notify();
it looks like the choice of the method which wakes up a thread affects how the thread that is woken up (and becomes RUNNABLE I guess) and the main thread (that has been BLOCKED) later compete for the lock — not something I would expect from the javadoc as well as searching the internet on the topic.
Or maybe I'm doing something wrong altogether?
Without looking too deeply into your code, I can see that you are using a single condition variable to implement a queue with one producer and more than one consumer. That's a recipe for trouble: If there's only one condition variable, then when a consumer calls notify(), there's no way of knowing whether it will wake the producer or wake the other consumer.
There are two ways out of that trap: The simplest is to always use notifyAll().
The other way is to stop using synchronized, wait(), and notify(), and instead use the facilities in java.util.concurrent.locks.
A single ReentrantLock object can give you two (or more) condition variables. Use one exclusively for the producer to notify the consumers, and use the other exclusively for the consumers to notify the producer.
Note: The names change when you switch to using ReentrantLocks: o.wait() becomes c.await(), and o.notify() becomes c.signal().
There appears to be some kind of fairness/barging going on using intrinsic locking - probably due to some optimization. I am guessing, that the native code checks to see if the current thread has notified the monitor it is about to wait on and allows it to win.
Replace the synchronized with ReentrantLock and it should work as you expect it. The different here is how the ReentrantLock handles waiters of a lock it has notified on.
Update:
Interesting find here. What you are seeing is a race between the main thread entering
synchronized (ctr) {
System.out.println(i + ":0 entered synchronized block");
ctr.addWhenHasSpace("hello");
ctr.addWhenHasSpace("world");
}
while the other two thread enter their respective synchronized regions. If the main thread does not get into its sync region before at least one of the two, you will experience this live-lock output you are describing.
What appears to be happening is that if both the two consumer threads hit the sync block first they will ping-pong with each other for notify and wait. It may be the case the JVM gives threads that are waiting priority to the monitor while threads are blocked.
i'm trying to solve the sleeping barber problem in java i'm having a problem when trying to make a thread leave the monitor when a signle condition is met here's the code:
public void getHairCut(String threadName) {
enter();
if(!barberSleeping) {
if(freeSeats == 0) {
System.out.println(threadName + " waiting...");
freeSeats--;;
hairCut.await();
}
else {
System.out.println("waiting room is full " + threadName + " is leaving...");
return; // i'm having a problem here,i want the thread to return from the method and release the monitor's lock to let other threads enter
}
}
// some code
leave();
}
thanks in advance.
Can't you wrap the critical section in a try-finally block?
public void getHairCut(String threadName) {
enter();
try {
if(!barberSleeping) {
if(freeSeats == 0) {
System.out.println(threadName + " waiting...");
freeSeats--;;
hairCut.await();
}
else {
System.out.println("waiting room is full " + threadName + " is leaving...");
return; // i'm having a problem here,i want the thread to return from the method and release the monitor's lock to let other threads enter
}
}
// some code
}
finally {
leave(); // this would be called in any case
}
}
The finally block will be executed in any case:
when execution reaches the bottom
when an exception is thrown
when the code block is quit because of a return statement
In very brief the situation is as follows:
In order to be capable of waiting for a condition to be met a thread (say T0) must first acquire a lock for itself. After that it might (or might not) be suspended because some condition is not yet met by calling a wait-function. If this condition will be met at a later point (by another thread e.g. T1, because T0 is suspended), T1 might signal the suspended Thread T0 to reclaim its work. In order to signal the condition which was responsible for suspending T0, T1 also needs to acquire the one lock associated with the condition.
A corresponding code would look like:
// relevant prior assumptions
Lock myLock = new ReentrantLock();
Condition myCondition = myLock.newCondition();
// code that might suspend thread T0
try {
myLock.lock();
while (someCondition == false) {
myCondition.await();
}
} finally {
myLock.unlock();
}
// code that signals T0 to wake up and continue with its wrkr where it stopped (which is exactly aone line after the call to myCondition.awayit())
try {
myLock.lock();
myCondition.signal();
} finally {
myLock.unlock();
}