Java Sync Lock

When we say that we lock an object using a synchronized keyword, does this mean that we acquire a lock for the entire object or only in the code that exists in the block?

In the following example, listOne.add synchronized, does this mean that if another thread accesses listOne.get , it will be blocked until the first thread exits this block? What if the second thread accesses the listTwo.get or listTwo.add in 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); } 
+4
source share
6 answers

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 cannot call a and b at the same time, since they are locked with the same lock. However, you can call a and c at the same time (obviously with multiple threads), since they are not locked on the same lock. This can lead to problems with listOne.

You can also call a and d at the same time, since d in this context is no different from c. He does not use the same lock.

It is important that you always block listOne with the same lock and not allow access to it without blocking. If listOne and listTwo are somehow related and sometimes need updates at the same time / atomically, you will need one lock to access both of them. Otherwise, 2 separate locks might be better.

Of course, you are likely to use the relatively new java.util.concurrent classes if all you need is a parallel list :)

+6
source

The lock is in the instance of the object that you include in the synchronized block.

But be careful! This object is NOT blocked for access by other threads. Only those threads that execute the same synchronized(obj) , where obj this in your example, but can also be a reference to variables in other threads, wait for this lock.

Thus, threads that do not perform any synchronized statements can access any and all variables of a “locked” object, and you are likely to encounter race conditions.

+6
source

Other threads will be blocked only if you have a synchronized block in one instance. Thus, no operations with the lists themselves will be blocked.

+3
source
 synchronized(this) { 

will block the this object. To lock and work with the listOne object:

 synchronized(listOne){ listOne.add(something); } 

so listOne accesses multiple threads one at a time.

See: http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html

+1
source

You need to understand that locking is advisory and not physically applied. For example, if you decide that you are going to use Object to block access to certain fields of classes, you should write code in such a way as to actually get a lock before accessing these fields. If you do not, you can access them and potentially cause deadlocks or other threading issues.

An exception is to use the synchronized for methods in which the runtime will automatically get a lock for you without having to do anything special.

+1
source

The Java language specification defines the value of a synchronized statement as follows:

Operator

A synchronized obtains a mutual exclusion lock (§17.1) on behalf of the executing thread, executes the block, and then releases the lock. While the executing thread holds the lock, no other thread can get the lock.

 SynchronizedStatement:` synchronized ( Expression ) Block` 

The type of the expression must be a reference type, or a compile-time error occurs.

The synchronized statement is executed by evaluating the expression first.

If for any reason the Expression evaluation terminates unexpectedly, then the synchronized statement terminates unexpectedly for the same reason.

Otherwise, if Expression is null, a NullPointerException is thrown.

Otherwise, let the non-empty value of the expression be V. The execution thread blocks the lock associated with V. Then the Block is executed. If the execution of the Block completes normally, the lock is unlocked, and the synchronized statement completes normally. If the execution of the Block terminates abruptly for any reason, the lock is unlocked, and the synchronized statement terminates abruptly for the same reason.

Acquiring a lock associated with an object does not in itself prevent other threads from accessing the fields of the object or calling unsynchronized methods on the object. Other threads may also use synchronized methods or a synchronized statement in the usual way to achieve mutual exclusion.

That is, in your example

 synchronized(this) { listOne.add(something); } 

the synchronized block processes the object referenced by listOne any special way, other threads can work with it at their discretion. However, it ensures that no other thread can simultaneously enter a synchronized block for the object referenced by this . Therefore, if all the code working with listOne is in synchronized blocks for the same object, no more than one thread can work with listOne at any given time.

Also note that the locked object does not receive special protection from the simultaneous access of its state, so the code

 void increment() { synchronized (this) { this.counter = this.counter + 1; } } void reset() { this.counter = 0; } 

it doesn’t synchronize properly, since the second thread can reset while the first thread has read, but not yet written, counter , as a result of which reset is overwritten.

0
source

Source: https://habr.com/ru/post/1345408/


All Articles