Possibility of exception after locking lock but before try-finally - java

I'm wondering if given code like
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
is there any chance that executing thread can be somehow terminated after executing lock method but before entering try-finally block? That would result in a lock that is taken but never freed. Is there some line in Java/JVM specification that gives us any assurance that if the code is written using that idiom there is no chance of leaving locked-forever lock?
My question is inspired by the answer to C# related question Can Monitor.Enter throw an exception? that references two posts on MSDN
https://blogs.msdn.microsoft.com/ericlippert/2007/08/17/subtleties-of-c-il-codegen/
https://blogs.msdn.microsoft.com/ericlippert/2009/03/06/locks-and-exceptions-do-not-mix/
about problems with code like
Monitor.Enter(...)
try
{
...
}
finally
{
Monitor.Exit(..)
}
that in case of C# there is small chance that execution never reaches try-finally based on machine code generated by JIT.
I'm aware that this may be seen as a contrived question/nitpicking but my curiosity got better of me.

Is there some line in Java/JVM specification that gives us any
assurance that if the code is written using that idiom there is no
chance of leaving locked-forever lock?
First of all i want to notice that in java there are structured and unstructured locks. Structured locks are that kind of locks where the locked code is encapsulated inside some structure (block) and is autoreleased in the end of this structure(block). There are as synchronized methods as synchronized blocks. In java you will get monitorenter (https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.monitorenter) instruction directly in bytecode only in case of using synchronized block. So if monitorenter instruction fails then this will be a fatal error which will cause jvm to stop. With syncrhonized method there is no monitorenter and monitorexit instructions directly in the the compile bytecode but that code in the syncrhonized block is marked for the jvm as synchronized and jvm will do that job by itself. So in this case if smth will go wrong then again this will be a fatal jvm error. So here the answer to your question is no because synchronized blocks or methods are compiled to native jvm instructions and their crashing will cause the whole jvm to crash.
Now let's talk about unstructered locks. These are locks where you have to take care about locking and unlocking by calling direct methods of that lock. Here you gain a lot of advantages of creating complex interesting constructions like chain locking and others. And again the answer to your question is no and actually it is absolutely possible for exception to be thrown in that method and it is also absolutely possible to get live or dead lock here. All this is possible due to the fact that unstructured locking is absolutely programmatic java concept. JVM knows nothing about unstructured locks. Lock in java is an interface (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html) and you can use OOB unstructered locks like Reentrant lock, Reentrant RW locks etc or write your custom implementation. But in the real life if you are using for example reentrant locks then there is almost no chance to get exception there. Even static analyzers will say you that there are no points in RLock where it is possible for exception to be thrown (as checked as unchecked). But what is possible is gettingan Error (https://docs.oracle.com/javase/7/docs/api/java/lang/Error.html) there. And again we come to a fatal JVM failure after which you wont need any locks. And instead of bytecode's monitorenter RLock and almost all other OOB java locks use AbstractQueuedSynchronizer (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/AbstractQueuedSynchronizer.html). So you can get sure that it is completely programmatic and JVM knows almost nothing about that.
Now from architecture perspective. If in some implementation you've got an unexpected exception inside the lock method and after that lock is still available for further usage then may be it would be better to get a forever living lock there instead of a lock with broken internal state. Its not safe to use it anymore and nobody guarantee correct further locking cause u have at least one precedent of incorrect behaviour. Any unexpected exception in lock should be considered as an issue which need deep investigation for it's initial reasons before further usage. And long living lock will prevent it's usage by other threads and, what is more important, system will preserve it's correct state. Then of course one day smb will m Concurrent computations in general are mostly about correctness.
Now about this question:
is there any chance that executing thread can be somehow terminated
after executing lock method but before entering try-finally block?
Answer for this is of course yes. You can even suspend thread holding the lock or just call sleep so other threads wont be able to acquire it. This is how locking algorithms work and nothing we can do about that. This will be classified as a bug. Actually lock-free 2+ threads algorithms are not vulnerable for such cases. Concurrent programming is not a simple thing. There are lot of things that you should think during it's design and even after that you wont avoid failures.

Related

Is it bad practice to use ReentrantLock instead of Synchronized? [duplicate]

java.util.concurrent API provides a class called as Lock, which would basically serialize the control in order to access the critical resource. It gives method such as park() and unpark().
We can do similar things if we can use synchronized keyword and using wait() and notify() notifyAll() methods.
I am wondering which one of these is better in practice and why?
If you're simply locking an object, I'd prefer to use synchronized
Example:
Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!
You have to explicitly do try{} finally{} everywhere.
Whereas with synchronized, it's super clear and impossible to get wrong:
synchronized(myObject) {
doSomethingNifty();
}
That said, Locks may be more useful for more complicated things where you can't acquire and release in such a clean manner. I would honestly prefer to avoid using bare Locks in the first place, and just go with a more sophisticated concurrency control such as a CyclicBarrier or a LinkedBlockingQueue, if they meet your needs.
I've never had a reason to use wait() or notify() but there may be some good ones.
I am wondering which one of these is better in practice and why?
I've found that Lock and Condition (and other new concurrent classes) are just more tools for the toolbox. I could do most everything I needed with my old claw hammer (the synchronized keyword), but it was awkward to use in some situations. Several of those awkward situations became much simpler once I added more tools to my toolbox: a rubber mallet, a ball-peen hammer, a prybar, and some nail punches. However, my old claw hammer still sees its share of use.
I don't think one is really "better" than the other, but rather each is a better fit for different problems. In a nutshell, the simple model and scope-oriented nature of synchronized helps protect me from bugs in my code, but those same advantages are sometimes hindrances in more complex scenarios. Its these more complex scenarios that the concurrent package was created to help address. But using this higher level constructs requires more explicit and careful management in the code.
===
I think the JavaDoc does a good job of describing the distinction between Lock and synchronized (the emphasis is mine):
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.
...
The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired.
While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way. For example, **some algorithms* for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.
With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used:
...
When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.
Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).
...
You can achieve everything the utilities in java.util.concurrent do with the low-level primitives like synchronized, volatile, or wait / notify
However, concurrency is tricky, and most people get at least some parts of it wrong, making their code either incorrect or inefficient (or both).
The concurrent API provides a higher-level approach, which is easier (and as such safer) to use. In a nutshell, you should not need to use synchronized, volatile, wait, notify directly anymore.
The Lock class itself is on the lower-level side of this toolbox, you may not even need to use that directly either (you can use Queues and Semaphore and stuff, etc, most of the time).
There are 4 main factors into why you would want to use synchronized or java.util.concurrent.Lock.
Note: Synchronized locking is what I mean when I say intrinsic locking.
When Java 5 came out with
ReentrantLocks, they proved to have
quite a noticeble throughput
difference then intrinsic locking.
If youre looking for faster locking
mechanism and are running 1.5
consider j.u.c.ReentrantLock. Java
6's intrinsic locking is now
comparable.
j.u.c.Lock has different mechanisms
for locking. Lock interruptable -
attempt to lock until the locking
thread is interrupted; timed lock -
attempt to lock for a certain amount
of time and give up if you do not
succeed; tryLock - attempt to lock,
if some other thread is holding the
lock give up. This all is included
aside from the simple lock.
Intrinsic locking only offers simple
locking
Style. If both 1 and 2 do not fall
into categories of what you are
concerned with most people,
including myself, would find the
intrinsic locking semenatics easier
to read and less verbose then
j.u.c.Lock locking.
Multiple Conditions. An object you
lock on can only be notified and
waited for a single case. Lock's
newCondition method allows for a
single Lock to have mutliple reasons
to await or signal. I have yet to
actually need this functionality in
practice, but is a nice feature for
those who need it.
I would like to add some more things on top of Bert F answer.
Locks support various methods for finer grained lock control, which are more expressive than implicit monitors (synchronized locks)
A Lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock.
Advantages of Lock over Synchronization from documentation page
The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way
Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).
A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection
ReentrantLock: In simple terms as per my understanding, ReentrantLock allows an object to re-enter from one critical section to other critical section . Since you already have lock to enter one critical section, you can other critical section on same object by using current lock.
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.
Apart from these three ReentrantLocks, java 8 provides one more Lock
StampedLock:
Java 8 ships with a new kind of lock called StampedLock which also support read and write locks just like in the example above. In contrast to ReadWriteLock the locking methods of a StampedLock return a stamp represented by a long value.
You can use these stamps to either release a lock or to check if the lock is still valid. Additionally stamped locks support another lock mode called optimistic locking.
Have a look at this article on usage of different type of ReentrantLock and StampedLock locks.
The main difference is fairness, in other words are requests handled FIFO or can there be barging? Method level synchronization ensures fair or FIFO allocation of the lock. Using
synchronized(foo) {
}
or
lock.acquire(); .....lock.release();
does not assure fairness.
If you have lots of contention for the lock you can easily encounter barging where newer requests get the lock and older requests get stuck. I've seen cases where 200 threads arrive in short order for a lock and the 2nd one to arrive got processed last. This is ok for some applications but for others it's deadly.
See Brian Goetz's "Java Concurrency In Practice" book, section 13.3 for a full discussion of this topic.
Major difference between lock and synchronized:
with locks, you can release and acquire the locks in any order.
with synchronized, you can release the locks only in the order it was acquired.
Brian Goetz's "Java Concurrency In Practice" book, section 13.3:
"...Like the default ReentrantLock, intrinsic locking offers no deterministic fairness guarantees, but the
statistical fairness guarantees of most locking implementations are good enough for almost all situations..."
Lock makes programmers' life easier. Here are a few situations that can be achieved easily with lock.
Lock in one method, and release the lock in another method.
If You have two threads working on two different pieces of code, however, in the first thread has a pre-requisite on a certain piece of code in the second thread (while some other threads also working on the same piece of code in the second thread simultaneously). A shared lock can solve this problem quite easily.
Implementing monitors. For example, a simple queue where the put and get methods are executed from many other threads. However, you do not want multiple put (or get) methods running simultaneously, neither the put and get method running simultaneously. A private lock makes your life a lot easier to achieve this.
While, the lock, and conditions build on the synchronized mechanism. Therefore, can certainly be able to achieve the same functionality that you can achieve using the lock. However, solving complex scenarios with synchronized may make your life difficult and can deviate you from solving the actual problem.
Lock and synchronize block both serves the same purpose but it depends on the usage. Consider the below part
void randomFunction(){
.
.
.
synchronize(this){
//do some functionality
}
.
.
.
synchronize(this)
{
// do some functionality
}
} // end of randomFunction
In the above case , if a thread enters the synchronize block, the other block is also locked. If there are multiple such synchronize block on the same object, all the blocks are locked. In such situations , java.util.concurrent.Lock can be used to prevent unwanted locking of blocks

What does "non-block-structured locking" mean?

I am reading Java Concurrency in Practice. In 13.1 Lock and ReentrantLock, it says:
Why create a new locking mechanism that is so similar to intrinsic locking? Intrinsic locking works fine in most situations but has some functional limitations— it is not possible to interrupt a thread waiting to acquire a lock, or to attempt to acquire a lock without being willing to wait for it forever. Intrinsic locks also must be released in the same block of code in which they are acquired; this simplifies coding and interacts nicely with exception handling, but makes non-block-structured locking disciplines impossible.
What does "non-block-structured locking" mean? I think it means that you can lock in one method, unlock in another method, like Lock, but intrinsic locks must be released in the same block of code in which they are acquired. Am I right?
But the Chinese version of that book translates "block" to "阻塞". Is it an error?
Block structured locking means that the pattern for acquiring and releasing locks mirrors the lexical code structure. Specifically, a section of code that acquires a lock is also responsible for releasing it; e.g.
Lock lock = ...
lock.acquire();
try {
// do stuff
} finally {
lock.release();
}
The alternative ("non-block-structured locking") simply means that the above constraint does not apply. You can do things like acquiring a lock in one method and releasing it in a different one. Or (hypothetically) even pass the lock to another thread to release1. The problem is that this kind of code is a lot harder to get correct, and a lot harder to analyze than the examples like the above.
1 - Beware. If you pass acquired locks between threads, you are liable to run into memory anomalies or worse. Indeed, I'm not even sure that it is legal in Java.
The "block structure" referred to in the quoted text is clearly talking about the lexical structure of the code, as per the Wikipedia article on the topic Block (programming). If the Chinese version of Java Concurrency in Practice uses characters that mean "blocking" in the sense of Blocking (programming), that is a mistranslation.

Java: Monitor the acquisition of Locks

I am currently experimenting a lot with java's security mechanisms in order to understand how to best execute untrusted code in a sandbox. One of the things you want to protect against are infinite loops which is why ideally you want to run the untrusted code in its own thread. Now, of course, malicious code could, for example, do some heavy processing resulting in a hanging thread. To get rid of this thread essentially the only way is to use java's deprecated Thread.stop() mechanism. The main reason this is problematic is that all of the locks held by the thread are released which could result in corrupted objects.
The question is: with Java's SecurityManager and custom classloaders I am able to track, for example, what classes can be loaded and what system resources can be accessed. Is there a way to be informed (and to potentially prohibit) code from acquiring locks (for example, defining a callback that is informed before the current thread goes into a synchronized block).
If you are already using a custom classloader, you could inspect the bytecode of each class before loading it and detect it if contains an instruction that grabs a lock (monitorenter).
You should also consider that locks released with stop() are only a problem if they are acquired on shared objects that other code might potentially lock. If you can avoid such objects to be accessible in the "evil" thread, you're safe.

Why can't I directly access (and lock) the implicit lock that Objects use for synchronized block

rephrased for clarity
I would like to be able to mix the use of the synchronized block with more explicit locking via calling lock and release methods directly when appropriate. Thus allowing me the syntaxtical sugar of using sychtronized(myObject) when I can get away with it, but also being able to call myObject.lock & myObject.unlock dierctly for those times when a synchronized block is not flexible enough to do what I need done.
I know that every single Object has, implicitly, a rentrant lock built into it which is used by the synchronized block. Effectively the the lock mthod is caled on the Objects internal reentrant lock every time one enters a sychronized block, and unlock is called on the same reentrant lock when you leave the synchronized block. I would seem as if it wouldn be easy enough to allow one the ability to manually lock/unlock this inplicit reentrant lock; thus allowing a mixing of synchronized blocks and explcit locking.
However, as far as I know there is no way to do this. And because of the way synchronized blocks work I don't believe there is a convenient way to mix them with explicit locking othewrise. It seems as if this would be a rather convenient, and easily added by expending the Object api to add lock/unlock methods.
The question I have is, why doesn't this exist? I'm certain there is a reason, but I don't know what it is. I thought the issue may be with encapsulation; same reason you don't want to do synchronize(this). However, if I am already calling sycnhronized(myObject) then by defination anyone who knows about myObject can likewise synchronize on it and cause a deadlock if done foolishly. The question of encapsulation comes down to who can access the object you synchronized on regardless of rather you use a sychtronized block or manually locked the object; at least as I see it. So is there some other advantage to not allowing one to manually lock an object?
The locks of a certain object is highly tied to the instance itself. The structure of the synchronized blocks and methods are very strict. If you, as a programmer, would have the possibility to interfere with the system (virtual machine), it could cause serious problems.
You could eventually release a lock that was created by a synchronized block
You create a lock that another synchronized block will release
You create more lock entries than exits
You create more lock exits than entries
There are even specific bytecodes defined for the lock and release operations. If you would have a "method" for this lock/unlock operation, it should be compiled to these bytecodes. So, it is really a low-level operation, and very much different from other Java object level implementations.
Synchronisation is a very strong contract. I think that the designers of the JLS did not want to allow the possibility to break this contract.
The Chapter 17 of the JLS describes more about the expected behaviour.

Synchronization vs Lock

java.util.concurrent API provides a class called as Lock, which would basically serialize the control in order to access the critical resource. It gives method such as park() and unpark().
We can do similar things if we can use synchronized keyword and using wait() and notify() notifyAll() methods.
I am wondering which one of these is better in practice and why?
If you're simply locking an object, I'd prefer to use synchronized
Example:
Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!
You have to explicitly do try{} finally{} everywhere.
Whereas with synchronized, it's super clear and impossible to get wrong:
synchronized(myObject) {
doSomethingNifty();
}
That said, Locks may be more useful for more complicated things where you can't acquire and release in such a clean manner. I would honestly prefer to avoid using bare Locks in the first place, and just go with a more sophisticated concurrency control such as a CyclicBarrier or a LinkedBlockingQueue, if they meet your needs.
I've never had a reason to use wait() or notify() but there may be some good ones.
I am wondering which one of these is better in practice and why?
I've found that Lock and Condition (and other new concurrent classes) are just more tools for the toolbox. I could do most everything I needed with my old claw hammer (the synchronized keyword), but it was awkward to use in some situations. Several of those awkward situations became much simpler once I added more tools to my toolbox: a rubber mallet, a ball-peen hammer, a prybar, and some nail punches. However, my old claw hammer still sees its share of use.
I don't think one is really "better" than the other, but rather each is a better fit for different problems. In a nutshell, the simple model and scope-oriented nature of synchronized helps protect me from bugs in my code, but those same advantages are sometimes hindrances in more complex scenarios. Its these more complex scenarios that the concurrent package was created to help address. But using this higher level constructs requires more explicit and careful management in the code.
===
I think the JavaDoc does a good job of describing the distinction between Lock and synchronized (the emphasis is mine):
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.
...
The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired.
While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way. For example, **some algorithms* for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.
With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used:
...
When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.
Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).
...
You can achieve everything the utilities in java.util.concurrent do with the low-level primitives like synchronized, volatile, or wait / notify
However, concurrency is tricky, and most people get at least some parts of it wrong, making their code either incorrect or inefficient (or both).
The concurrent API provides a higher-level approach, which is easier (and as such safer) to use. In a nutshell, you should not need to use synchronized, volatile, wait, notify directly anymore.
The Lock class itself is on the lower-level side of this toolbox, you may not even need to use that directly either (you can use Queues and Semaphore and stuff, etc, most of the time).
There are 4 main factors into why you would want to use synchronized or java.util.concurrent.Lock.
Note: Synchronized locking is what I mean when I say intrinsic locking.
When Java 5 came out with
ReentrantLocks, they proved to have
quite a noticeble throughput
difference then intrinsic locking.
If youre looking for faster locking
mechanism and are running 1.5
consider j.u.c.ReentrantLock. Java
6's intrinsic locking is now
comparable.
j.u.c.Lock has different mechanisms
for locking. Lock interruptable -
attempt to lock until the locking
thread is interrupted; timed lock -
attempt to lock for a certain amount
of time and give up if you do not
succeed; tryLock - attempt to lock,
if some other thread is holding the
lock give up. This all is included
aside from the simple lock.
Intrinsic locking only offers simple
locking
Style. If both 1 and 2 do not fall
into categories of what you are
concerned with most people,
including myself, would find the
intrinsic locking semenatics easier
to read and less verbose then
j.u.c.Lock locking.
Multiple Conditions. An object you
lock on can only be notified and
waited for a single case. Lock's
newCondition method allows for a
single Lock to have mutliple reasons
to await or signal. I have yet to
actually need this functionality in
practice, but is a nice feature for
those who need it.
I would like to add some more things on top of Bert F answer.
Locks support various methods for finer grained lock control, which are more expressive than implicit monitors (synchronized locks)
A Lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock.
Advantages of Lock over Synchronization from documentation page
The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way
Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).
A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection
ReentrantLock: In simple terms as per my understanding, ReentrantLock allows an object to re-enter from one critical section to other critical section . Since you already have lock to enter one critical section, you can other critical section on same object by using current lock.
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.
Apart from these three ReentrantLocks, java 8 provides one more Lock
StampedLock:
Java 8 ships with a new kind of lock called StampedLock which also support read and write locks just like in the example above. In contrast to ReadWriteLock the locking methods of a StampedLock return a stamp represented by a long value.
You can use these stamps to either release a lock or to check if the lock is still valid. Additionally stamped locks support another lock mode called optimistic locking.
Have a look at this article on usage of different type of ReentrantLock and StampedLock locks.
The main difference is fairness, in other words are requests handled FIFO or can there be barging? Method level synchronization ensures fair or FIFO allocation of the lock. Using
synchronized(foo) {
}
or
lock.acquire(); .....lock.release();
does not assure fairness.
If you have lots of contention for the lock you can easily encounter barging where newer requests get the lock and older requests get stuck. I've seen cases where 200 threads arrive in short order for a lock and the 2nd one to arrive got processed last. This is ok for some applications but for others it's deadly.
See Brian Goetz's "Java Concurrency In Practice" book, section 13.3 for a full discussion of this topic.
Major difference between lock and synchronized:
with locks, you can release and acquire the locks in any order.
with synchronized, you can release the locks only in the order it was acquired.
Brian Goetz's "Java Concurrency In Practice" book, section 13.3:
"...Like the default ReentrantLock, intrinsic locking offers no deterministic fairness guarantees, but the
statistical fairness guarantees of most locking implementations are good enough for almost all situations..."
Lock makes programmers' life easier. Here are a few situations that can be achieved easily with lock.
Lock in one method, and release the lock in another method.
If You have two threads working on two different pieces of code, however, in the first thread has a pre-requisite on a certain piece of code in the second thread (while some other threads also working on the same piece of code in the second thread simultaneously). A shared lock can solve this problem quite easily.
Implementing monitors. For example, a simple queue where the put and get methods are executed from many other threads. However, you do not want multiple put (or get) methods running simultaneously, neither the put and get method running simultaneously. A private lock makes your life a lot easier to achieve this.
While, the lock, and conditions build on the synchronized mechanism. Therefore, can certainly be able to achieve the same functionality that you can achieve using the lock. However, solving complex scenarios with synchronized may make your life difficult and can deviate you from solving the actual problem.
Lock and synchronize block both serves the same purpose but it depends on the usage. Consider the below part
void randomFunction(){
.
.
.
synchronize(this){
//do some functionality
}
.
.
.
synchronize(this)
{
// do some functionality
}
} // end of randomFunction
In the above case , if a thread enters the synchronize block, the other block is also locked. If there are multiple such synchronize block on the same object, all the blocks are locked. In such situations , java.util.concurrent.Lock can be used to prevent unwanted locking of blocks

Categories

Resources