Explicit Locks vs Implicit Locks - java

Is using Locks (java.util.concurrent.locks.Lock) instead of keyword synchronized + method wait() and method notify() totally the same?
Can I thread-safely program using locks (explicit locks) rather than implicit locks (synchronized)?
As of know I have always been using implicit locks. I am aware of the advantages given by the Lock interface implementation like methods: isLocked(), getLockQueueLength(), getHoldCount(), etc... however still the old school way (wait() and notify()) would have other limits other than not having those methods?
I am also aware of the possibility of constructing a lock with a (boolean fairness) parameter which allows lack of starvation.

Yes, absolutely you can write thread-safe program using java.util.concurrent.locks.Lock. If you see any implementation of java.util.concurrent.locks.Lock like ReentrantLock internal implementation uses old synchronized blocks.
Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects.
Adding to my difference the synchronized keyword has naturally built in language support. This can mean the JIT can optimise synchronised blocks in ways it cannot with Locks. e.g. it can combine synchronized blocks.synchronized is best for a small number of threads accessing a lock and Lock may be best for a high number of threads accessing the same locks . Also synchronized block makes no guarantees about the sequence in which threads waiting to entering it are granted access.

Locks and synchronized blocks have the same semantics and provide the same guarantees from a Java Memory Model perspective. The main difference is that Locks provide more control (such as with tryLock or when asking a lock to be fair etc.) which allow for a more flexible and fine-grained lock management.
However, when you don't need those additional features, it is better to use a plain old synchronized block as it reduces the room for error (e.g. you can't "forget" to unlock it).

Related

Confused about synchronization and thread safe ? java

Actually, I am a bit confused in regards of several explanation from website or blog about synchronization and thread-safe. I've done some research on different class of Core Java Api or Java Framework (Collections). And i've often noticed that some class are synchronize and thread-safe which means, at a time, only one thread can access the code.
But i need some precision :
A class is synchronize so its thread-safe ?
Or synchronize and thread-safe have two different meaning ?
Best regards
A class is synchronize so its thread-safe ?
A class is not synchronized. Rather a method, or a block of code is synchronized.
Synchronization (using synchronized) is one way to make code thread-safe. There are other ways.
Or synchronize and thread-safe have two different meaning ?
Yes. They have different meanings.
And i've often noticed that some class are synchronize and thread-safe which means, at a time, only one thread can access the code.
Actually, if you "noticed" that, you were not paying attention!
With a synchronized method, only one thread can access the code while holding a given lock; i.e. you get mutual exclusion. If two threads use different locks, then you won't get mutual exclusion.
The other thing to note is that merely using synchronized does not guarantee thread-safety. You need to use it in the right way:
threads need to synchronize on the appropriate objects / locks
threads need to synchronize in all appropriate code
if the code entails acquiring multiple locks, the locks need to be acquired in an order that avoids deadlocks.

Why intrinsic lock like synchronized is discouraged [duplicate]

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.

Threadsafe vs Synchronized

I'm new to java.
I'm little bit confused between Threadsafe and synchronized.
Thread safe means that a method or class instance can be used by multiple threads at the same time without any problems occurring.
Where as Synchronized means only one thread can operate at single time.
So how they are related to each other?
The definition of thread safety given in Java Concurrency in Practice is:
A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
For example, a java.text.SimpleDateFormat object has internal mutable state that is modified when a method that parses or formats is called. If multiple threads call the methods of the same dateformat object, there is a chance a thread can modify the state needed by the other threads, with the result that the results obtained by some of the threads may be in error. The possibility of having internal state get corrupted causing bad output makes this class not threadsafe.
There are multiple ways of handling this problem. You can have every place in your application that needs a SimpleDateFormat object instantiate a new one every time it needs one, you can make a ThreadLocal holding a SimpleDateFormat object so that each thread of your program can access its own copy (so each thread only has to create one), you can use an alternative to SimpleDateFormat that doesn't keep state, or you can do locking using synchronized so that only one thread at a time can access the dateFormat object.
Locking is not necessarily the best approach, avoiding shared mutable state is best whenever possible. That's why in Java 8 they introduced a date formatter that doesn't keep mutable state.
The synchronized keyword is one way of restricting access to a method or block of code so that otherwise thread-unsafe data doesn't get corrupted. This keyword protects the method or block by requiring that a thread has to acquire exclusive access to a certain lock (the object instance, if synchronized is on an instance method, or the class instance, if synchronized is on a static method, or the specified lock if using a synchronized block) before it can enter the method or block, while providing memory visibility so that threads don't see stale data.
Thread safety is a desired behavior of the program, where the synchronized block helps you achieve that behavior. ​There are other methods of obtaining Thread safety e.g immutable class/objects. Hope this helps.
Thread safety: A thread safe program protects it's data from memory consistency errors. In a highly multi-threaded program, a thread safe program does not cause any side effects with multiple read/write operations from multiple threads on shared data (objects). Different threads can share and modify object data without consistency errors.
synchronized is one basic method of achieving ThreadSafe code.
Refer to below SE questions for more details:
What does 'synchronized' mean?
You can achieve thread safety by using advanced concurrency API. This documentation page provides good programming constructs to achieve thread safety.
Lock Objects support locking idioms that simplify many concurrent applications.
Concurrent Collections make it easier to manage large collections of data, and can greatly reduce the need for synchronization.
Atomic Variables have features that minimize synchronization and help avoid memory consistency errors.
ThreadLocalRandom (in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads.
Refer to java.util.concurrent and java.util.concurrent.atomic packages too for other programming constructs.
Related SE question:
Synchronization vs Lock
Synchronized: only one thread can operate at same time.
Threadsafe: a method or class instance can be used by multiple threads at the same time without any problems occurring.
If you relate this question as, Why synchronized methods are thread safe? than you can get better idea.
As per the definition this appears to be confusive. But not,if you understand it analytically.
Synchronized means: sequentially one by one in an order,Not concurrently [Not at the same time].
synchronized method not allows to act another thread on it, While a thread is already working on it.This avoids concurrency.
example of synchronization: If you want to buy a movie ticket,and stand in a queue. you will get the ticket only after the person in front of you get the ticket.
Thread safe means: method becomes safe to be accessed by multiple threads without any problem at the same time.synchronized keyword is one of the way to achieve 'thread safe'. But Remember:Actually while multiple threads tries to access synchronized method they follow the order so becomes safe to access. Actually, Even they act at the same time, but cannot access the same resource(method/block) at the same time, because of synchronized behavior of the resource.
Because If a method becomes synchronized, so this is becomes safe to allow multiple threads to act on it, without any problem. Remember:: multiple threads "not act on it at the same time" hence we call synchronized methods thread safe.
Hope this helps to understand.
After patiently reading through a lot of answers and not being too technical at the same time, I could say something definite but close to what Nayak had already replied to fastcodejava above, which comes later on in my answer but look
synchronization is not even close to brute-forcing thread-safety; it's just making a piece of code (or method) safe and incorruptible for a single authorized thread by preventing it from being used by any other threads.
Thread safety is about how all threads accessing a certain element behave and get their desired results in the same way if they would have been sequential (or even not so), without any form of undesired corruption (sorry for the pleonasm) as in an ideal world.
One of the ways of achieving proximity to thread-safety would be using classes in java.util.concurrent.atomic.
Sad, that they don't have final methods though!
Nayak, when we declare a method as synchronized, all other calls to it from other threads are locked and can wait indefinitely. Java also provides other means of locking with Lock objects now.
You can also declare an object to be final or volatile to guarantee its availability to other concurrent threads.
ref: http://www.javamex.com/tutorials/threads/thread_safety.shtml
In practice, performance wise, Thread safe, Synchronised, non-thread safe and non-synchronised classes are ordered as:
Hashtable(slower) < Collections.SynchronizedMap < HashMap(fastest)

Why use a ReentrantLock if one can use synchronized(this)?

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.

Trade offs between using Java's built in concurency mechanism versus Utilities provided in java.util.concurrent

What are the trade offs between using Java's built in concurency mechanism versus utilities (like ReentrantLocks for example) provided in java.util.concurrent
There are two main differences:
The java.util.concurrent classes represent a higher level of abstraction and tested implementations of specific concepts. You could implement most or all of those concepts using just synchronization, but it would be more code, more work, and much, much more error-prone.
Some of those classes are based on atomic hardware operations (compare and set) instead of sychronization, which performs better than sychronization under heavy (but not extreme) contention.
These come to mind:
The "synchronized" feature is a language construct and has special flow control for entering and exiting blocks whereas the "util.concurrent" must obey the rules of any other object. This will incur some cognitive load for programmers.
The "util.concurrent" interfaces and implementations can define their own unique behaviors (such as fairness, or separate read/write locks) so there is room for improved performance in specific situations.
The "util.concurrent.atomic" classes can provide hardware-level support for compare-and-swap instructions which enable lock-free and wait-free algorithms which can be have better performance in some applications.
Advantages of synchronized:
Obviously, using a simply synchronized block (or method) is easier from the syntax side, and you can't forget the unlock() step.
Advantages of Lock:
With explicit Lock objects, on the other hand, you can have non-nested protected blocks - like when iterating over a linked list, you may always want to lock the next list element and only after this unlock the previous one.
A Lock object allows blocking non-interruptible, blocking interruptible and non-blocking acquiring of a lock, while a synchronized block only allows the blocking non-interruptible one.
There are other Lock implementations allowing different locking strategies (like ReadWriteLock).
There are no tradeoffs, only pitfalls.
Almost no one uses wait(), notify() and notifyAll() to implement concurrency control, unless they are writing some construct not available in java.util.concurrent. It is very hard to get right, even for Doug Lea (author of Concurrent Programming in Java and JSR-166 spec lead).
Synchronized works for simple cases, but does not give the needed granularity (multiple reader, single writer locks are something not supported by synchronized alone, although you could use it to implement semaphores and then implement RW locks, but you would be reinventing the wheel).

Categories