In the solution to an programming exercise concerning locks, I've noticed they were using an Object to syncronize on, so something like:
Lock lock = new ReentrantLock();
Object obj = new Object();
and in a method:
synchronized(obj){
obj.wait();}
my question is, could I have used a Condition instead, let's say:
Condition cond = lock.newCondition();
and then use, in the method,
cond.await()
instead, without putting it in a synhronized block?
edit: the solution:
How would I implement this with the Condition?
Yes. But you have to aquire the lock first. See the doc of Condition.await():
The current thread is assumed to hold the lock associated with this
Condition when this method is called. It is up to the implementation
to determine if this is the case and if not, how to respond.
Typically, an exception will be thrown (such as
IllegalMonitorStateException) and the implementation must document
that fact.
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
is similar with
ReentrantLock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
while (<condition does not hold>)
cond.await();
}
} finally {
lock.unlock();
}
Related
I am trying to understand what is the use of doing condition.await() if I am already doing lock.lock()
If I understood locks correctly, once I do lock.lock() it will not proceed any further if some other thread has a lock.
So, in this case if pushToStack() has acquired a lock by doing lock.lock() then what is the use of checking for stackEmptyCondition.await() in the popFromStack() method? Because anyway, the code will stop at the lock.lock() line in the popFromStack() method. What am I missing/wrong?
public class ReentrantLockWithCondition {
Stack<String> stack = new Stack<>();
int CAPACITY = 5;
ReentrantLock lock = new ReentrantLock();
Condition stackEmptyCondition = lock.newCondition();
Condition stackFullCondition = lock.newCondition();
public void pushToStack(String item){
try {
lock.lock();
while(stack.size() == CAPACITY) {
stackFullCondition.await();
}
stack.push(item);
stackEmptyCondition.signalAll();
} finally {
lock.unlock();
}
}
public String popFromStack() {
try {
lock.lock(); // we are blocked here to acquire a lock
while(stack.size() == 0) {
stackEmptyCondition.await(); // then why do we need to check this again?
}
return stack.pop();
} finally {
stackFullCondition.signalAll();
lock.unlock();
}
}
}
The point is the Condition, not the Lock.
It is often the case that a program needs to wait until either "something happens" or "something is in a particular state". The Condition represents what you're waiting for.
In order to program such a thing safely, some sort of locking is needed. If you're waiting for something to be in a particular state, you really want it to remain in that state while you do whatever you had in mind when you decided to wait for it. That's where the Lock comes in.
In your example, you want to wait until the stack is not full, and when you discover that the stack is not full, you want it to stay not-full (that is, prevent some other thread from pushing on to the stack) while you push something on that stack.
If Condition could be used separately itself and creating code is merely:
final ConditionObject newCondition() {
return new ConditionObject();
}
why it's not created just this way?
In class ArrayBlockingQueue there is code in constructor:
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
where both notEmpty and notFull are instances of Condition class.
From the documentation of Condition:
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.
A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock instance use its newCondition() method.
As explained, a Condition instance must be associated with a Lock instance1. Having Lock function as a factory for creating instances of Condition makes perfect sense with that in mind as it implies the relationship between the two. Another way this relationship could have been enforced is to give Condition a constructor which accepts a Lock instance, but since Condition is also an interface it cannot declare constructors. I'm also of the opinion that a no-argument factory method is more user friendly in this case anyway.
Note: If it's not already clear, the ReentrantLock class is an implementation of the Lock interface and the ConditionObject class is an implementation of the Condition interface.
The other problem with attempting to use ConditionObject directly is that it's an inner class (i.e. non-static nested class) of AbstractQueuedSynchronizer2. This means you would need an instance of the latter class in order to create an instance of the former class. However, the implementation of AbstractQueuedSynchronizer used by ReentrantLock is an implementation detail and not exposed to the public. In other words, you have no way to call the constructor of ConditionObject which means the only way to create an instance is via newCondition().
To recap, there's at least three reasons why a factory method is used to create Condition objects:
It makes the relationship between Lock and Condition clear.
With both Lock and Condition being interfaces, you need a way to associate a Condition with a Lock without knowing about the implementations. Otherwise it would not be possible to "program to an interface".
Due to ConditionObject being an inner class it cannot be instantiated directly—at least, not by code which doesn't have access to an instance of the enclosing class.
1. The methods of Condition only make sense in the context of owning a Lock. Just like how a thread must be synchronized on an object before it can legally invoke that object's monitor methods (i.e. wait/notify), a thread must own the associated Lock before it can legally invoke the methods of the Condition (i.e. await/signal).
2. There's also AbstractQueuedLongSynchronizer which declares its own ConditionObject inner class. While the class has the same name as the one declared by AbstractQueuedSynchronizer, the two are actually separate classes.
Locks and Conditions provide a mechanism that was previously (pre 1.5) available only through synchronization, wait/notify and custom condition code.
Here's an idiomatic example
synchronized(foo) { // Lock
while(!conditionMet) // Condition
foo.wait(); // Condition.signalAll();
// Condition met, do something and notify
conditionMet = false;
foo.notifyAll();
}
It might seem that the condition isn't related to the lock object in any way, but that guarantees thread safety. You can't write the above code without access to the condition being inside the synchronized block. (You can access the condition boolean from non-threadsafe code and mess things up, but you can always mess things up).
The whole ReentrantLock class is actually a functionality wrapper over the Sync class object, which is responsible for the low level synchronization and the creation of conditions. Conditions are bound to a specific Lock (or Sync rather) to basically make sure that they're thread-safe. As the Javadoc for Condition states
Because access to this shared state information occurs in different
threads, it must be protected, so a lock of some form is associated
with the condition.
As mentioned by Slaw, instantiating a new Condition separately just doesn't make sense as it will lost association with the original Lock object, and it would just similar to creating a new Condition from another Lock (because java.util.concurrent.locks.Condition cannot be instantiated separately).
We can refer to below 2 examples to understand more:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest {
final ReentrantLock lock = new ReentrantLock();
final Condition notEmpty = lock.newCondition();
final Condition notFull = lock.newCondition();
String message;
boolean ready;
boolean isCompleted;
public void consume() {
ReentrantLock lock = this.lock;
lock.lock();
try {
while(!ready)
notEmpty.await();
System.out.println("Received message: " + message);
ready = !ready; // reverse the "ready" state
notFull.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void publish(String message) {
ReentrantLock lock = this.lock;
lock.lock();
try {
while(ready)
notFull.await();
System.out.println("Adding message");
this.message = message;
ready = !ready; // reverse the "ready" state
notEmpty.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ConditionTest ct = new ConditionTest();
Thread msgProducerThread = new Thread(() -> {
List<String> messages = new ArrayList<String>();
messages.add("Hello!");
messages.add("here we get a message");
messages.add("then we get another message");
messages.forEach(m -> ct.publish(m));
ct.isCompleted = true;
});
Thread msgConsumerThread = new Thread(() -> {
while (!ct.isCompleted)
ct.consume();
});
msgProducerThread.start();
msgConsumerThread.start();
}
}
Then we would get below result which means the Lock and Condition are functioning properly:
Adding message
Received message: hello
Adding message
Received message: current project is complete
Adding message
Received message: here is the estimation for new project
However, if we try to use separate Condition by replacing the original code:
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();
with :
ReentrantLock lock2 = new ReentrantLock(fair);
ReentrantLock lock3 = new ReentrantLock(fair);
Condition notEmpty = lock2.newCondition();
Condition notFull = lock3.newCondition();
Then, it would get:
Adding message
Exception in thread "Thread-0" Received message: Hello!
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1939)
at ConditionTest.publish(ConditionTest.java:54)
at ConditionTest.lambda$0(ConditionTest.java:75)
at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1939)
at ConditionTest.consume(ConditionTest.java:33)
at ConditionTest.lambda$1(ConditionTest.java:83)
at java.lang.Thread.run(Thread.java:745)
Which means there are no relevant association between the Condition and the Lock, which leads to IllegalMonitorStateException being thrown.
The normal pattern with ReentrantLock and lock()/unlock() is like this:
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
Can this be refactored to
synchronized(lck) {
// ...
}
?
And why?
These are different things. synchronized is built into the language and can be used with any object. What it does is lock its intrinsic lock. Every single object has one. As it's a built-in mechanism, you don't need a try-finally block—the lock is always unlocked when the control exits the synchronized block. So as long as your code actually exits that block, the lock will be unlocked.
ReentrantLock is a special class. It locks some special internal object, that is probably implementation-specific. It does not lock its intrinsic lock. You could, of course, lock that one too—but it doesn't normally make any sense. This code will almost certainly deadlock, for example:
final ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
System.out.println("Thread 1 locked the lock");
try { Thread.sleep(100); } catch (Exception ex) {}
synchronized (lock) {
System.out.println("Thread 1 locked lock's intrinsic lock");
}
} finally {
lock.unlock();
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 locked lock's intrinsic lock");
try { Thread.sleep(200); } catch (Exception ex) {}
lock.lock();
try {
System.out.println("Thread 2 locked the lock");
} finally {
lock.unlock();
}
}
}).start();
It deadlocks because two threads lock two different things in different order.
It certainly feels like ReentrantLock does almost the same thing as synchronized. It works similarly, but synchronized is both more convenient and less powerful. So unless you need any features of ReentrantLock, like interruptible lock attempts or lock time-outs, you should stick with synchronized for the purpose of reentrant locking, and use any objects for that. Simple private final Object lock = new Object() will do just fine. Note that final will prevent confusing things that could happen if you change that object at some moment; some IDEs will issue a warning if you omit final.
I assume that you are aware of differences in explicit and implicit locking provided by Lock and synchronized respectively.
I believe you are looking for a reason saying what's wrong in using instances of class implementing Lock interfaces inside synchronized block as in synchronized(lock).
Could it be refactored? Yes.
But should you be doing that? Not with instances of classes implementing Lock interface
Why? - Well.
It is all right if you just use lock only inside synchronized however you leave the possibility to other developers to misuse the code say for e.g. what if someone tomorrow tries calling Lock methods inside synchronized(lock) something like below.
Lock lock = new ReentrantLock();
synchronized(lock){ //You write this
// lock.lock(); // I am not taking a lock here
System.out.println("See emily play");
...
...
... // after 100 lines of code
//callAnotherMethod(lock); //Someone else does this
lock.unlock(); //Someone else does this
}
The above code is horrible but to give you an example, in the above example if you do not call lock(), then you end up with IllegalMonitorStateException. If you do call (uncomment above) lock.lock() it makes no difference.
Not to mention the callAnotherMethod(lock) where you are passing the lock instance and what sort of unexpected behaviours it can introduce.
Keep in mind that is one such example.
Bottom line, if it works correctly by any chance, it is just wasting resources and time and would serve no advantage/purpose. More importantly there is no guarantee that it would not introduce regressions in the future. And if there would be any such regressions, you may end up wasting significant amount of time because of misuse of concepts.
Softwares are always designed with Open-Close principle. You would be writing the code that would violate it very clearly.
In case if you do want to use fine grained locks using synchronized then you can make use of the below
Object obj1 = new Object();
Object obj2 = new Object();
public void doSomething(){
synchronised(obj1){
...
}
}
public void doSomethingMore(){
synchronised(obj2){
...
}
}
But then again, I don't see any reason why you would not use multiple lock instances to achieve the above.
I have:
static public final ReentrantLock lock = new ReentrantLock();
static public Condition my_condition = lock.newCondition();
in myClass_1 and in myClass_2 class I call:
synchronized (myClass_1.my_condition){
myClass_1.my_condition.signalAll();
}
This is giving me the java.lang.IllegalMonitorStateException. I am already synchronizing over the signall() call. What could be causing it?
This is because you are not getting the lock of ReentrantLock before signalling.
Read below important statements from ReentrantLock#newCondition
If this lock is not held when any of the Condition waiting or
signalling methods are called, then an IllegalMonitorStateException is
thrown.
Also, read below from Condition. Now, like you cannot call wait() if thread is not acquiring the lock, same you wait or signal conditions if lock is not acquired.
Where a Lock replaces the use of synchronized methods and statements,
a Condition replaces the use of the Object monitor methods.
Bottom line: Acquire the lock before waiting or signalling the Condition.
lock.lock(); //Get the lock
while(/* whatever is your condition in myClass_1 and myClass_2 */){ //Or negative condition you want, but some code logic condition...
my_condition.await();
}
my_condition_2.signal(); //If you want to notify one thread. Like in case of Java's blocking queue, if you want to notify one thread to put or take.
my_condition_2.signalAll(); //If you want to notify all threads.
Do not use synchronized with Locks. Locks and Conditions replace synchronized/wait/notify; they should never be used in combination with it.
The documentation for ReeantrantLock.newCondition states:
If this lock is not held when any of the Condition waiting or signalling methods are called, then an IllegalMonitorStateException is thrown.
Correct use of a Lock and Condition looks like this:
lock.lock();
try {
someFlag = true;
condition.signalAll();
} finally {
lock.unlock();
}
And elsewhere:
lock.lock();
try {
someFlag = false;
while (!someFlag) {
condition.await();
}
} finally {
lock.unlock();
}
All Condition.await* methods must be called in a while-loop that checks the data the Condition represents, since the await* methods are subject to spurious wakeups (just like the Object.wait* methods).
I was just curious is it possible that a thread T1 say executes a synchronization block partially and then releases the lock on the object and another thread T2 executes the same block? Something like this:
line1: synchronized(this){
line2: if(INSTANCE == null)
line3: INSTANCE = new Object(); //say a variable is initialized
line4: return INSTANCE;
line5: }
Is it possible that thread T1 acquires a lock on current object (this) and executes line1 and line2. Then thread T1 is preempted by thread T2, T1 releases lock and T2 acquires lock on this and executes the same block (all the lines1 to 5). Then thread T1 again takes the lock and continues executing from line3?
Basically, T1 will see INSTANCE as null and so will T2 and each will create a new Object.
If this is not possible can someone explain why not?
Addendum:
Thanks everyone for your answer. My question was a bit misleading. What I am exactly asking, is it possible that once a thread is executing a synchronized block it can release the lock before the entire block is executed (not by explicitly calling wait() but something which is process, CPU dependent)? Is there a contract in JLS or a JVM guarantee that once a thread starts executing a synchronized block the lock on the object is not released until the end of the block? My understanding is synchronization guarantees no 2 threads can simultaneously execute the block (or other synchronized method/block) but the lock is hold until the end of the block is reached? It's kind of obvious but is it specified in the JLS?
Thread preemption doesn't cause the preempted thread to release its locks. If it did, locks would be worthless. The whole point of a synchronized block is that it will disallow other threads from synchronizing on the same object until the thread releases the lock (by leaving the synchronized block).
Even if a thread is preempted, it won't release a lock. The lock is still held. If another thread comes along, it will block (stop running) until the lock is released, even if the original thread gets preempted several times before it releases the lock. Basically almost any kind of lock has some storage in the heap that gets written to indicate there's a lock. It's permanent until the thread or the system writes a different value to indicate the lock is free.
It is of course possible to write code that allows access to an instance or field without ever taking the lock, but that's a coding error. It's also possible for the original thread to exit the block early (say it throws an exception) -- this releases the lock, and other threads can continue as normal.
I'm pretty sure it's not possible for a second thread to enter the synchronize block before the first one has executed the entire block. On obtaining the lock on the object, all other threads attempting to enter the synchronized code will be blocked.
See more information here: http://tutorials.jenkov.com/java-concurrency/synchronized.html
Basically you can use Locks objects. Lock objects can allow you to sequentially apply and release locks on multiple locks line by line.
A very good tutorial on how to implement it here
Check out below code:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class test2{
private static Object instance = null;
private static test2 t = new test2();
private static Lock lock = new ReentrantLock();
public static void main(String[] args) {
A a = new A();
B b = new B();
a.setName("Thread-A");
b.setName("Thread-B");
a.start();
b.start();
}
public Object getObj(){
try {
lock.lock();
System.out.println("Begin Current thread: "+ Thread.currentThread().getName());
if(instance == null){
if(Thread.currentThread().getName().equalsIgnoreCase("Thread-A")){
lock.unlock();
while(instance==null){
System.out.println(Thread.currentThread().getName() +" : instance is null");
}
while(true){
if(!lock.tryLock()){
System.out.println(Thread.currentThread().getName() + " waiting for re lock");
}else{
lock.lock();
break;
}
}
}
instance =new Object();
System.out.println("End Current thread: "+ Thread.currentThread().getName());
if (((ReentrantLock) lock).isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
public static class A extends Thread{
#Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
public static class B extends Thread{
#Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
}
Output
Begin Current thread: Thread-A
Thread-A : instance is null
Begin Current thread: Thread-B
Thread-A : instance is null
End Current thread: Thread-B
Thread-A waiting for re lock
End Current thread: Thread-A