When we say we lock on an object using the synchronized keyword, does it mean we are acquiring a lock on the whole object or only at the code that exists in the block?
In the following example listOne.add is synchronized, does it mean if another thread accesses listOne.get it would be blocked until the first thread gets out of this block? What if a second thread accesses the listTwo.get or listTwo.add methods on the instance variables of the same object when the first thread is still in the synchronized block?
List<String> listONe = new ArrayList<String>();
List<String> listTwo = new ArrayList<String>();
/* ... ... ... */
synchronized(this) {
listOne.add(something);
}
Given the methods:
public void a(String s) {
synchronized(this) {
listOne.add(s);
}
}
public void b(String s) {
synchronized(this) {
listTwo.add(s);
}
}
public void c(String s) {
listOne.add(s);
}
public void d(String s) {
synchronized(listOne) {
listOne.add(s);
}
}
You can not call a and b at the same time, as they are locked on the same lock.
You can however call a and c at the same time (with multiple threads obviously) as they are not locked on the same lock. This can lead to trouble with listOne.
You can also call a and d at the same time, as d is no different in this context from c. It does not use the same lock.
It is important that you always lock listOne with the same lock, and allow no access to it without a lock. If listOne and listTwo are somehow related and sometimes need updates at the same time / atomically you'd need one lock for access to both of them. Otherwise 2 separate locks may be better.
Of course, you'd probably use the relatively new java.util.concurrent classes if all you need is a concurrent list :)
The lock is on the object instance that you include in the synchronized block.
But take care! That object is NOT intrinsically locked for access by other threads. Only threads that execute the same synchronized(obj), where obj is this in your example but could in other threads also be a variable reference, wait on that lock.
Thus, threads that don't execute any synchronized statements can access any and all variables of the 'locked' object and you'll probably run into race conditions.
Other threads will block only on if you have a synchronized block on the same instance. So no operations on the lists themselves will block.
synchronized(this) {
will only lock the object this. To lock and work with the object listOne:
synchronized(listOne){
listOne.add(something);
}
so that listOne is accessed one at a time by multiple threads.
See: http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html
You need to understand that the lock is advisory and is not physically enforced. For example if you decided that you where going to use an Object to lock access to certain class fields, you must write the code in such a way to actually acquire the lock before accessing those fields. If you don't you can still access them and potentially cause deadlocks or other threading issues.
The exception to this is the use of the synchronized keyword on methods where the runtime will automatically acquire the lock for you without you needing to do anything special.
The Java Language specification defines the meaning of the synchronized statement as follows:
A synchronized statement acquires a mutual-exclusion lock (ยง17.1) on behalf of the executing thread, executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock.
SynchronizedStatement:`
synchronized ( Expression ) Block`
The type of Expression must be a reference type, or a compile-time error occurs.
A synchronized statement is executed by first evaluating the Expression.
If evaluation of the Expression completes abruptly for some reason, then the synchronized statement completes abruptly for the same reason.
Otherwise, if the value of the Expression is null, a NullPointerException is thrown.
Otherwise, let the non-null value of the Expression be V. The executing thread locks the lock associated with V. Then the Block is executed. If execution of the Block completes normally, then the lock is unlocked and the synchronized statement completes normally. If execution of the Block completes abruptly for any reason, then the lock is unlocked and the synchronized statement then completes abruptly for the same reason.
Acquiring the lock associated with an object does not of itself prevent other threads from accessing fields of the object or invoking unsynchronized methods on the object. Other threads can also use synchronized methods or the synchronized statement in a conventional manner to achieve mutual exclusion.
That is, in your example
synchronized(this) {
listOne.add(something);
}
the synchronized block does treat the object referred to by listOne in any special way, other threads may work with it as they please. However, it ensures that no other thread may enter a synchronized block for the object referred to by this at the same time. Therefore, if all code working with listOne is in synchronized blocks for the same object, at most one thread may work with listOne at any given time.
Also note that the object being locked on gets no special protection from concurrent access of its state, so the code
void increment() {
synchronized (this) {
this.counter = this.counter + 1;
}
}
void reset() {
this.counter = 0;
}
is incorrectly synchronized, as a second thread may execute reset while the first thread has read, but not yet written, counter, causing the reset to be overwritten.
Related
I'm a newbie to threads and specifically the synchronized key word.
I understand that a thread's state changes to BLOCKED if it tried to access a synchronized block where another thread already owns the lock.
For reference:
synchronized (objA){
objA.methodA();
}
//some code
objA.methodB();
My question is whether another thread can alter the object objA through another independent method (methodB() in this example). Or does owning the lock mean that no other thread can access/alter objA in any way ie whether or not the alteration code is within the synchronized block?
No. The only thing that owning the monitor (lock) means, is that no other thread can also own it until you give it up.
Of course, that does mean that they can't call any synchronized methods on objA (since that requires acquiring the lock), so if all of the modification methods on objA are synchronized (or use synchronized (this) {...} blocks), then the "no" becomes a "yes."
But if methodB never tries to lock on this (either by being synchronized, or by using a synchronized block), then no amount of locking on objA will block calls to objA.methodB().
Synchronizing on a object locks the monitor of the object.
It means that no synchronized method or synchronized statement on an object can be executed if a thread is already executing in a synchronized statement (or a synchronized method) on this same object.
But things are different for no synchronized methods.
Indeed, any thread may invoke any no synchronized method on objA while a thread is executing in a synchronized statement on this same objA.
Given that there's only one lock for each instance of a class, then why doesn't Java just allow us to do this:
void method() {
synchronized {
// do something
}
// do other things
}
instead of this:
void method() {
synchronized (lock) {
// do something
}
// do other things
}
What's the purpose of specifying a lock? Does it make a difference if I choose one object as a lock over the other? Or could I just choose any random object?
EDIT:
It turned out that my comprehension of synchronized methods is wrong at the fundamental level.
I thought different synchronized methods or blocks are entirely independent of each other regardless of locks. Rather, all synchronized methods or blocks with the same lock can be accessed only by one thread, even if such synchronized methods/blocks are from different classes (the documentation should have emphasized this more: ALL synced methods/blocks, regardless of location, all that matters is the lock).
Given that there's only one lock for each instance of a class, then why doesn't Java just allow us to do this:
void method() {
synchronized {
// do something
}
// do other things
}
Although an intrinsic lock is provided with each instance,
that's not necessarily the "obvious" lock to use.
You're perhaps right that they could have provided synchronized { ... } as a shorthand for synchronized (this) { ... }.
I don't know why they didn't, but I never missed it.
But concurrent programming is tricky,
so making the lock object an explicit required parameter may make things clearer to readers, which is a good thing, as #ajb pointed out in a comment.
In any case, I don't think syntax is your main question, so let's move on.
What's the purpose of specifying a lock?
Uhm, the lock is perhaps the single most important thing in the synchronization mechanism. The key point in synchronization is that only one thread can hold the same lock. Two threads holding different locks are not synchronized. So knowing what is the lock guarding the synchronization is crucial.
Does it make a difference if I choose one object as a lock over the other?
I hope the previous section makes it clear that yes, you have to choose the object carefully. It has to be an object visible by all threads involved,
it has to be not null, and it has to be something that won't get reassigned during the period of synchronization.
Or could I just choose any random object?
Certainly not. See the previous section.
To understand concurrency in Java, I recommend the book Java Concurrency in Practice by one of the authors of the API, or Oracle's tutorials on the subject.
It's so you can lock on something completely different than this.
Remember how Vector is "thread-safe?" It's not quite that simple; each call is, but code like this isn't because it could have been updated between getting the size of the vector and getting the element:
for (int i = 0; i < vector.size(); ++i) System.out.println(vector.get(i));
Since Vector, along with Collections.synchronized*, is synchronized with the older synchronized keyword, you can make that above code thread-safe by enclosing it all within a lock:
synchronized (vector) {
for (int i = 0; i < vector.size(); ++i) System.out.println(vector.get(i));
}
This could be in a method that isn't thread-safe, isn't synchronized, or uses ReentrantLock; locking the vector is separate from locking this.
It most certainly makes a difference what object you use as a lock. If you say
void method() {
synchronized (x) {
// do something
}
// do other things
}
Now, if one thread is executing the block and another tries to enter the block, if x is the same for both of them, then the second thread will have to wait. But if x is different, the second thread can execute the block at the same time. So, for example, if method is an instance method and you say
void method() {
synchronized (this) {
// do something
}
// do other things
}
Now two threads running the method using the same object can't execute the block simultaneously, but two threads can still run the method on different objects without blocking each other. This is what you'd want when you want to prevent simultaneous access to the instance variables in that object, but you don't have anything else you need to protect. It's not a problem if two threads are accessing variables in two different objects.
But say the block of code is accessing a common resource, and you want to make sure all other threads are locked out of accessing that resource. For example, you're accessing a database, and the block does a series of updates and you want to make sure they're done atomically, i.e. no other code should access the database while you're in between two updates. Now synchronized (this) isn't good enough, because you could have the method running for two different objects but accessing the same database. In this case, you'd need a lock that is the same for all objects that might access the same database. Here, making the database object itself the lock would work. Now no two threads can use method to enter this block at the same time, if they're working with the same database, even if the objects are different.
if you have multiple objects b1/b2 needs to update concurrency
class A {
private B b1, b2;
}
if you have only one lock say class A itself
synchronized (this) { ... }
then assume there are two threads are updating b1 and b2 in the same time, they will play one by one because synchronized (this)
but if you have two locks for b1 and b2
private Object lock1 = new Object, lock2 = new Object;
the two threads i've mentioned will play concurrently because synchronized (lock1) not affect synchronized (lock2).sometimes means better performance.
In synchronized (lock).., lock can be an object level lock or it can be class level lock.
Example1 Class Level Lock:
private static Object lock=new Object();
synchronized (lock){
//do Something
}
Example2 Object Level Lock:
private Object lock=new Object();
synchronized (lock){
//do Something
}
I'm wondering if there is an easy way to make a synchronized lock that will respond to changing references. I have code that looks something like this:
private void fus(){
synchronized(someRef){
someRef.roh();
}
}
...
private void dah(){
someRef = someOtherRef;
}
What I would like to happen is:
Thread A enters fus, and acquires a lock on someref as it calls roh(). Assume roh never terminates.
Thread B enters fus, begins waiting for someRef` to be free, and stays there (for now).
Thread C enters dah, and modifies someRef.
Thread B is now allowed to enter the synchronized block, as someRef no longer refers to the object Thread A has a lock on.
What actually happens is:
Thread A enters fus, and acquires a lock on someref as it calls roh(). Assume roh never terminates.
Thread B enters fus, finds the lock, and waits for it to be released (forever).
Thread C enters dah, and modifies someRef.
Thread B continues to wait, as it's no longer looking at someref, it's looking at the lock held by A.
Is there a way to set this up such that Thread B will either re-check the lock for changing references, or will "bounce off" into other code? (something like sychronizedOrElse?)
There surely is a way, but not with synchronized. Reasoning: At the point in time, where the 2nd thread enters fus(), the first thread holds the intrinsic lock of the object referenced by someRef. Important: the 2nd thread will still see someRef referencing on this very object and will try to acquire this lock. Later on, when the 3rd thread changes the reference someRef, it would have to notify the 2nd thread somehow about this event. This is not possible with synchronized.
To my knowledge, there is no built-in language-feature like synchronized to handle this kind of synchronization.
A somewhat different approach would be to either manage a Lock within your class or give someRef an attribute of type Lock. Instead of working with lock() you can use tryLock() or tryLock(long timeout, TimeUnit unit). This is a scheme on how I would implement this (assuming that someRef has a Lock attribute):
volatile SomeRef someRef = ... // important: make this volatile to deny caching
...
private void fus(){
while (true) {
SomeRef someRef = this.someRef;
Lock lock = someRef.lock;
boolean unlockNecessary = false;
try {
if (lock.tryLock(10, TimeUnit.MILLISECONDS)) { // I have chonse this arbritrarily
unlockNecessary = true;
someRef.roh();
return; // Job is done -> return. Remember: finally will still be executed.
// Alternatively, break; could be used to exit the loop.
}
} catch (InterruptException e) {
e.printStackTrace();
} finally {
if (unlockNecessary) {
lock.unlock();
}
}
}
}
...
private void dah(){
someRef = someOtherRef;
}
Now, when someRef is changed, the 2nd thread will see the new value of someRef in its next cycle and therefore will try to synchronize on the new Lock and succeed, if no other thread has acquired the Lock.
What actually happens is ... Thread B continues to wait, as it's no longer looking at someref, it's looking at the lock held by A.
That's right. You can't write code to synchronize on a variable. You can only write code to synchronize on some object.
Thread B found the object on which to synchronize by looking at the variable someref, but it only ever looks at that variable one time to find the object. The object is what it locks, and until thread A releases the lock on that object, thread B is going to be stuck.
I would like to add some more info on top of excellent answers by #Turing85 and #james large.
I agree that Thread B continues to wait.
It's better to avoid synchronization for this type of program by using better lock free API.
Atomic variables have features that minimize synchronization and help avoid memory consistency errors.
From the code you have posted, AtomicReference seems to be right solution for your problem.
Have a look at documentation page on Atomic package.
A small toolkit of classes that support lock-free thread-safe programming on single variables. In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:
boolean compareAndSet(expectedValue, updateValue);
One more nice post in SE related to this topic.
When to use AtomicReference in Java?
Sample code:
String initialReference = "value 1";
AtomicReference<String> someRef =
new AtomicReference<String>(initialReference);
String newReference = "value 2";
boolean exchanged = someRef.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);
Refer to this jenkov tutorial for better understanding.
As shown in example below, once lock is taken on an object in call method, there is no need for further methods to have synchronized keyword.
public class Prac
{
public static void main(String[] args)
{
new Prac().call();
}
private synchronized void call()
{
further();
}
private synchronized void further()
{
oneMore();
}
private synchronized void oneMore()
{
// do something
}
}
But, if I still add synchronized keyword to further and onceMore, what java does on such encounters? Does java checks if lock is required or not? or as method call is in same stack, it just proceeds without checking if lock is required or not as lock is already acquired.
Note : My doubt is how java will behave in such situation, I am not sure, but I think it is different from biased locking.
In fact, java checks if the current thread has the lock every time it enters a synchronized method.
private synchronized void oneMore()
{
// do something
}
This is equivalent to
private void oneMore(){
synchronized(this){
// do something
}
}
But because of the fact that intrinsic locks in java are reentrant; if a thread has the lock, it doesn't reacquire it once it enters another synchronized block as in you example. Otherwise, this will create a deadlock.
Update: To answer your comment below. From Java Concurency in practice:
Reentrancy is implemented by associating with each lock an acquisition count
and an owning thread. When the count is zero, the lock is considered unheld.
When a thread acquires a previously unheld lock, the JVM records the owner
and sets the acquisition count to one. If that same thread acquires the lock
again, the count is incremented, and when the owning thread exits the
synchronized block, the count is decremented. When the count reaches zero,
the lock is released.
Therefore, checking if a lock is acquired, is equivalent to an if statement (more or less) that the variable holding the owning thread is equal or not to the thread trying to acquire the lock.
However, as you pointed out, there is no need for the synchronized keyword on the private methods. In general, you should try to remove unnecessary synchronization since that usually leads to degraded performance.
My understanding of volatile is that it ensures that the value is always read from memory, so as far as I can see, in the following example, the myObject variable would need to be volatile to avoid a NullPointerException being raised:
private final Object lock = new Object();
private MyObject myObject = null;
//...
synchronized (lock) {
if (myObject == null) {
myObject = new MyObject();
}
myObject.blah();
// some other stuff that I want synchronized
}
myObject is only ever touched in the synchronized block. lock is only every used to synchronize that block.
Is that correct?
So rephrased slightly, my question is...imagine two threads are hitting that code. First thread locks and sets myObject, calls .blah() and any other code within the synchronized block and exits the synchronized block. This allows thread two to enter the synchronized block. Without setting myObject to volatile, is there are chance it could still evaluate myObject == null to true?
The synchronized block will ensure the updates to memory is seen by other threads. There is no need to make myObject volatile.
From Intrinsic Locks and Synchronization:
When a thread releases an intrinsic lock, a happens-before
relationship is established between that action and any subsequent
acquistion of the same lock.
I think volatile is not needed here, because every thread which goes into synchronized block is checking myObject references, so myObject should be instantieted when first thread goes into block, other threads are secured by checking is myObject not null. For me looks good.
EDIT: I hope there is only this one block where you want to use myObect reference, and you do not change this reference before or after synchoronize block.