Related
Let's say you have two threads, thread1 and thread2. If you call thread1.start() and thread2.start() at the same time and they both print out numbers between 1 and 5, they will both run at the same time and they will randomly print out the numbers in any order, if I am not mistaken. To prevent this, you use the .join() method to make sure that a certain thread gets executed first. If this is what the .join() method does, what is the Lock object used for?
Thread.join is used to wait for another thread to finish. The join method uses the implicit lock on the Thread object and calls wait on it. When the thread being waited for finishes it notifies the waiting thread so it can stop waiting.
Java has different ways to use locks to protect access to data. There is implicit locking that uses a lock built into every Java object (this is where the synchronized keyword comes in), and then there are explicit Lock objects. Both of them protect data from concurrent access, the difference is the explicit Locks are more flexible and powerful, while implicit locking is designed to be easier to use.
With implicit locks, for instance, I can't not release the lock at the end of a synchronized method or block, the JVM makes sure that the lock gets released as the thread leaves. But programming with implicit locks can be limiting. For instance, there aren't separate condition objects so if there are different threads accessing a shared object for different things, notifying only a subset of them is not possible.
With explicit Locks you get separate condition objects and can notify only those threads waiting on a particular condition (producers might wait on one condition while consumers wait on another, see the ArrayBlockingQueue class for an example), and you can implement more involved kinds of patterns, like hand-over-hand locking. But you need to be much more careful, because the extra features introduce complications, and releasing the lock is up to you.
Locking typically prevents more than one thread from running a block of code at the same time. This is because only ONE thread at a time can acquire the lock and run the code within. If a thread wants the lock but it is already taken, then that thread goes into a wait state until the lock is released. If you have many threads waiting for the lock to be released, which one gets the lock next is INDETERMINATE (can't be predicted). This can lead to "thread starvation" where a thread is waiting for the lock, but it just never gets it because other threads always seem to get it instead. This is a very generic answer because you didn't specify a language. Some languages may differ slightly in that they might have a determinate method of deciding who gets the lock next.
I have and application made in java that uses an reentrant global lock and I have a problem like this:
One thread is acquire the reentrant global lock and let say that is keeping the lock 30 seconds in this interval of time it makes some operations. In this interval of time all other threads are blocked.
My problem is that I want some threads like RMI to have the chance to execute.
What would be a good locking policy or optimization in order to let some other threads to acquire the lock for a short period of time ?
So you basically have a job queue which should be executed in a single-threaded environent. Each time before polling from this queue you need to sort it's entries by priority.
abstract class JobEntry<V> implements Callable<V>{
Date registeredAt;
long runEstimationMs;
JobType type;
}
So you could come up with a weighing function for this entry and sort entries based on it or with implementing Comparable.
And this is almost it. You could send these jobs to a fixed thread pool of a single thread. If you need to interrupt them, you would need to cancel the future and each job should check Thread.interrupted() state.
The most difficult part here is the weighing function, a possible way to build it could be making a set of experiments on your system.
If one thread has acquired lock other threads cant proceed , we can not change this behavior.
Now to solve your problem there are few suggestions I want to give.
Try to Reduce lock scope so that other threads also get chance for execution.
Look at the possibility if you can acquire lock for really required part and release lock after that. Because as you said one thread is taking good amount of time there could be some part of code where you don't need locking.
operationInLock(){
----
lock.lock();
Code where lock is required;
lock.unlock();
Code where lock is Not required;
Code where lock is Not required;
Code where lock is Not required;
lock.lock();
Code where lock is required;
lock.unlock();
Code where lock is Not required;
Code where lock is Not required;
Code where lock is Not required;
}
If you don't feel this answer useful , give us some more info about code/functionality because without seeing code it becomes very difficult to give solution we can just give u suggestions based on best practice.
I believe this can be achieved via acquiring on only particular section of code by first thread which has global lock for 30 seconds and also you can also use Read and write separate locks which comes with ReadWriteLock Object in java.
ReadWriteLock is implemented by ReentrantReadWriteLock Class in java.util.concurrent.locks package.Multiple Threads can acquire multiple read Locks, but only a single Thread can acquire mutually-exclusive write Lock .Other threads requesting readLocks have to wait till the write Lock is released. A thread is allowed to degrade from write lock to read lock but not vice-versa. Allowing a read thread to upgrade would lead to a deadlock as more than one thread can try to upgrade its lock. The ReentrantReadWriteLock also supports all the features of the Reentrant lock like providing the fair mechanism, reentrant locks, Condition Support (on a write Lock only), allowing interruption on read as well as write Locks.
. A Condition object, also known as condition variable, provides a thread with the ability to suspend its execution, until the condition is true. A Condition object is necessarily bound to a Lock and can be obtained using the newCondition() method.
Furthermore, a Condition enables the effect of having multiple wait-sets per object, by combining these sets with the use of a Lock implementation. Moreover, due to the fact that Conditions access portions of state shared among different threads, the usage of a Lock is mandatory. It is important to mention that a Condition must atomically release the associated Lock and suspend the current’s thread execution.
For your reference I am giving you the URLs ->
https://examples.javacodegeeks.com/core-java/util/concurrent/locks-concurrent/condition/java-util-concurrent-locks-condition-example/
https://examples.javacodegeeks.com/core-java/util/concurrent/locks-concurrent/readwritelock/java-readwritelock-example/
Please let me know if you need other help
Out of curiosity, when Java implements wait() and notify() methods, are they really just using locks? i.e., wait() acquires a mutex, notify() release a mutex, notifyAll() releases all mutexes (in the same object, of course)?
Other than being less cumbersome than using locks, are there other advantages of using wait() and notify()?
[EDIT] I realized what I confused myself about after Brian's comments:
wait doesn't lock, it releases the lock and passes it to someone else who's waiting on a synchronized statement for the mutex, then waits to be notified by someone else who has the lock and calls notify, which passes the lock back to the original thread that called wait. I think that's where you're getting confused. – Brian 17 mins ago
The other questions have focused on what the language says that wait and notify are - but that doesn't seem to be what your question is about... you talk about mutexes, which is an implementation detail and therefore JVM specific.
So we need to pick a JVM - let's pick openjdk (source available here). The bit of code that (ultimately) handles all this stuff is found at hotspot/src/share/vm/runtime/objectMonitor.cpp.
This maintains two datastructures - a wait set and an entry set. Waiting threads are added to the wait set and parked whereas threads attempting to take the monitor are added to the entry set and then parked. On notify a thread is taken from the wait set and added to the entry set. When a thread releases the lock it unparks a thread from the entry set if there is one. Note that these sets are actually implemented as queues (linked lists) so are treated on a FIFO basis.
Therefore, in this particular case the implementation treats waiting on an object's monitor and attempting to take an object's monitor in a similar way.
But this is just one implementation of one JVM (although it's likely that others do something similar) - so we cannot rely on it. So I suppose the question is why do you want to know? If it's just curiosity then look through the openjdk code, it's fascinating. If you plan on using this information in your code... don't.
UPDATE
I realise that saying "park" doesn't tell us much. The code that parks a thread is platform specific (and is implemented in an object called PlatformEvent, which ParkEvent extends). In the version of openjdk that I'm looking at the park code for linux can be found at hotspot/src/os/linux/vm/os_linux.cpp and this calls pthread_mutex_lock(_mutex)... so in answer to your question yes calling wait may take a mutex on my machine. Note that there's lots of stuff that happens above this which might prevent us getting to this point.
wait() and notify() don't do any monitor acquisition. as the javadoc for these methods state, the caller must have acquired the monitor before calling. in fact, wait() actually releases the monitor the caller acquired (although, i guess technically wait does do monitor (re)acquisition before finally returning).
wait releases the lock you already have with the intention of re-obtaining it at some point in the future after someone else calls notify. This is in addition to the locking mechanisms provided by synchronized. Basically, you use synchronized to obtain a lock, then you use wait, notify, and notifyAll to control how those locks are released and re-locked.
Out of curiosity, when Java implements wait() and notify() methods, are they really just using locks?
i.e., wait() acquires a mutex, notify() release a mutex, notifyAll() releases all mutexes?
Sorry, but none of that quite right. :)
It is the synchronized keyword that obtains the monitor. i.e. this is a form of locking. NB: using java.util.concurrent.locks.Lock does something similar.
wait() causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. Nothing to do with locking - but can only call this method when the current thread current thread already own's this object's monitor (in a synchronized block/method)
notify() wakes up a single thread that is waiting on this object's monitor. Again, nothing to do with locking - but can only call this method when the current thread current thread already own's this object's monitor (in a synchronized block/method)
wait(), notify() always work along with Synchronization , so comparison can be between Locks and synchronization. There is big difference between Locks like RentrantLock, ReadWriteLock and Synchronization [block, methods].
Locks dont use synchronization internally while wait(), notify() will need synchronization.
You use Lock along with java.util.concurrent.locks.Condition, which efficiently enables conditional locking, this is quite tedious to implement with synchronization..
You dont have any tryLock option with synchronization , you either take lock or wait. But with Lock interface you have the choice.
I'm trying to understand what makes the lock in concurrency so important if one can use synchronized (this). In the dummy code below, I can do either:
synchronized the entire method or synchronize the vulnerable area (synchronized(this){...})
OR lock the vulnerable code area with a ReentrantLock.
Code:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
A ReentrantLock is unstructured, unlike synchronized constructs -- i.e. you don't need to use a block structure for locking and can even hold a lock across methods. An example:
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
Such flow is impossible to represent via a single monitor in a synchronized construct.
Aside from that, ReentrantLock supports lock polling and interruptible lock waits that support time-out. ReentrantLock also has support for configurable fairness policy, allowing more flexible thread scheduling.
The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. Note however, that fairness of locks does not guarantee fairness of thread scheduling. Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. Also note that the untimed tryLock method does not honor the fairness setting. It will succeed if the lock is available even if other threads are waiting.
ReentrantLock may also be more scalable, performing much better under higher contention. You can read more about this here.
This claim has been contested, however; see the following comment:
In the reentrant lock test, a new lock is created each time, thus there is no exclusive locking and the resulting data is invalid. Also, the IBM link offers no source code for the underlying benchmark so its impossible to characterize whether the test was even conducted correctly.
When should you use ReentrantLocks? According to that developerWorks article...
The answer is pretty simple -- use it when you actually need something it provides that synchronized doesn't, like timed lock waits, interruptible lock waits, non-block-structured locks, multiple condition variables, or lock polling. ReentrantLock also has scalability benefits, and you should use it if you actually have a situation that exhibits high contention, but remember that the vast majority of synchronized blocks hardly ever exhibit any contention, let alone high contention. I would advise developing with synchronization until synchronization has proven to be inadequate, rather than simply assuming "the performance will be better" if you use ReentrantLock. Remember, these are advanced tools for advanced users. (And truly advanced users tend to prefer the simplest tools they can find until they're convinced the simple tools are inadequate.) As always, make it right first, and then worry about whether or not you have to make it faster.
One final aspect that's gonna become more relevant in the near future has to do with Java 15 and Project Loom. In the (new) world of virtual threads, the underlying scheduler would be able to work much better with ReentrantLock than it's able to do with synchronized, that's true at least in the initial Java 15 release but may be optimized later.
In the current Loom implementation, a virtual thread can be pinned in two situations: when there is a native frame on the stack — when Java code calls into native code (JNI) that then calls back into Java — and when inside a synchronized block or method. In those cases, blocking the virtual thread will block the physical thread that carries it. Once the native call completes or the monitor released (the synchronized block/method is exited) the thread is unpinned.
If you have a common I/O operation guarded by a synchronized, replace the monitor with a ReentrantLock to let your application benefit fully from Loom’s scalability boost even before we fix pinning by monitors (or, better yet, use the higher-performance StampedLock if you can).
ReentrantReadWriteLock is a specialized lock whereas synchronized(this) is a general purpose lock. They are similar but not quite the same.
You are right in that you could use synchronized(this) instead of ReentrantReadWriteLock but the opposite is not always true.
If you'd like to better understand what makes ReentrantReadWriteLock special look up some information about producer-consumer thread synchronization.
In general you can remember that whole-method synchronization and general purpose synchronization (using the synchronized keyword) can be used in most applications without thinking too much about the semantics of the synchronization but if you need to squeeze performance out of your code you may need to explore other more fine-grained, or special-purpose synchronization mechanisms.
By the way, using synchronized(this) - and in general locking using a public class instance - can be problematic because it opens up your code to potential dead-locks because somebody else not knowingly might try to lock against your object somewhere else in the program.
From oracle documentation page about ReentrantLock:
A reentrant mutual exclusion Lock with the same basic behaviour and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.
A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock.
The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order.
ReentrantLock key features as per this article
Ability to lock interruptibly.
Ability to timeout while waiting for lock.
Power to create fair lock.
API to get list of waiting thread for lock.
Flexibility to try for lock without blocking.
You can use ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock to further acquire control on granular locking on read and write operations.
Have a look at this article by Benjamen on usage of different type of ReentrantLocks
Synchronized locks does not offer any mechanism of waiting queue in which after the execution of one thread any thread running in parallel can acquire the lock. Due to which the thread which is there in the system and running for a longer period of time never gets chance to access the shared resource thus leading to starvation.
Reentrant locks are very much flexible and has a fairness policy in which if a thread is waiting for a longer time and after the completion of the currently executing thread we can make sure that the longer waiting thread gets the chance of accessing the shared resource hereby decreasing the throughput of the system and making it more time consuming.
You can use reentrant locks with a fairness policy or timeout to avoid thread starvation. You can apply a thread fairness policy. it will help avoid a thread waiting forever to get to your resources.
private final ReentrantLock lock = new ReentrantLock(true);
//the param true turns on the fairness policy.
The "fairness policy" picks the next runnable thread to execute. It is based on priority, time since last run, blah blah
also,
Synchronize can block indefinitely if it cant escape the block. Reentrantlock can have timeout set.
One thing to keep in mind is :
The name 'ReentrantLock' gives out a wrong message about other locking mechanism that they are not re-entrant. This is not true. Lock acquired via 'synchronized' is also re-entrant in Java.
Key difference is that 'synchronized' uses intrinsic lock ( one that every Object has ) while Lock API doesn't.
I think the wait/notify/notifyAll methods don't belong on the Object class as it pollutes all objects with methods that are rarely used. They make much more sense on a dedicated Lock class. So from this point of view, perhaps it's better to use a tool that is explicitly designed for the job at hand - ie ReentrantLock.
Lets assume this code is running in a thread:
private static ReentrantLock lock = new ReentrantLock();
void accessResource() {
lock.lock();
if( checkSomeCondition() ) {
accessResource();
}
lock.unlock();
}
Because the thread owns the lock it will allow multiple calls to lock(), so it re-enter the lock. This can be achieved with a reference count so it doesn't has to acquire lock again.
Someone at work just asked for the reasoning behind having to wrap a wait inside a synchronized.
Honestly I can't see the reasoning. I understand what the javadocs say--that the thread needs to be the owner of the object's monitor, but why? What problems does it prevent? (And if it's actually necessary, why can't the wait method get the monitor itself?)
I'm looking for a fairly in-depth why or maybe a reference to an article. I couldn't find one in a quick google.
Oh, also, how does thread.sleep compare?
edit: Great set of answers--I really wish I could select more than one because they all helped me understand what was going on.
Lots of good answers here already. But just want to mention here that the other MUST DO when using wait() is to do it in a loop dependent on the condition you are waiting for in case you are seeing spurious wakeups, which in my experience do happen.
To wait for some other thread to change a condition to true and notify:
synchronized(o) {
while(! checkCondition()) {
o.wait();
}
}
Of course, these days, I'd recommend just using the new Condition object as it is clearer and has more features (like allowing multiple conditions per lock, being able to check wait queue length, more flexible schedule/interrupt, etc).
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
while (! checkCondition()) {
condition.await();
}
} finally {
lock.unlock();
}
}
If the object does not own the object monitor when it calls Object.wait(), it will not be able to access the object to setup a notify listener until the the monitor is released. Instead, it will be treated as a thread attempting to access a method on a synchronized object.
Or to put it another way, there is no difference between:
public void doStuffOnThisObject()
and the following method:
public void wait()
Both methods will be blocked until the object monitor is released. This is a feature in Java to prevent the state of an object from being updated by more than one thread. It simply has unintended consequences on the wait() method.
Presumably, the wait() method is not synchronized because that could create situations where the Thread has multiple locks on the object. (See Java Language Specifications/Locking for more info on this.) Multiple locks are a problem because the wait() method will only undo one lock. If the method were synchronized, it would guarantee that only the method's lock would be undone while still leaving a potential outer lock undone. This would create a deadlock condition in the code.
To answer your question on Thread.sleep(), Thread.sleep() does not guarantee that whatever condition you are waiting on has been met. Using Object.wait() and Object.notify() allows a programmer to manually implement blocking. The threads will unblock once a notify is sent that a condition has been met. e.g. A read from disk has finished and data can be processed by the thread. Thread.sleep() would require the programmer to poll if the condition has been met, then fall back to sleep if it has not.
It needs to own the monitor, since the purpose of the wait() is to release the monitor and let other threads obtain the monitor to do processing of their own. The purpose of these methods (wait/notify) is to coordinate access to synchronized code blocks between two threads that require each other to perform some functionality. It is not simply a matter of making sure access to a data structure is threadsafe, but to coordinate events between multiple threads.
A classic example would be a producer/consumer case where one thread pushes data to a queue, and another thread consumes the data. The consuming thread would always require the monitor to access the queue, but would release the monitor once the queue is empty. The producer thread would then only get access to write to the thread when the consumer is no longer processing. It would notify the consumer thread once it has pushed more data into the queue, so it can regain the monitor and access the queue again.
Wait gives up the monitor, so you must have it to give it up. Notify must have the monitor as well.
The main reason why you want to do this is to ensure that you have the monitor when you come back from wait() -- typically, you are using the wait/notify protocol to protect some shared resource and you want it to be safe to touch it when wait returns. The same with notify -- usually you are changing something and then calling notify() -- you want to have the monitor, make changes, and call notify().
If you made a function like this:
public void synchWait() {
syncronized { wait(); }
}
You would not have the monitor when wait returned -- you could get it, but you might not get it next.
Here's my understanding on why the restriction is actually a requirement. I'm basing this on a C++ monitor implementation I made a while back by combining a mutex and a condition variable.
In a mutex+condition_variable=monitor system, the wait call sets the condition variable into a wait state and releases the mutex. The condition variable is shared state, so it needs to be locked to avoid race conditions between threads that want to wait and threads that want to notify. Instead of introducing yet another mutex to lock its state, the existing mutex is used. In Java, the mutex is correctly locked when the about-to-wait thread owns the monitor.
Mostly wait is done if there is a condition say a queue is empty.
If(queue is empty)
queue.wait();
Let us assume the queue is empty.
In case if the current thread pre-empts after checking the queue, then if another
thread adds few elements to queue, the current thread will not know and will go for wait
state. Thats wrong.
So we should have something like
Synchornized(queue)
{
if(queue is empty)
queue.wait();
}
Now let us consider what if they made wait itself as synchronized. As already mentioned in one of the comments, it releases only one lock. That means if wait() was synchronized in the above code only one lock would have been released. Implies that current thread will go for wait with the lock for the queue.