You are on page 1of 5

JAVA SYNCHRONIZED BLOCK

• a synchronized block can only be executed by a single thread at a time


• Java's 1st mechanism for synchronizing access to objects shared by multiple threads
• not a very advanced mechanism though
• we use synchronized keyword on some objects
• all synchronized blocks on the same object can only have one thread executing inside them at a time
• others attempting to enter are blocked until the thread inside the synchronized block exits
• 4 different types of synchronized usage:
1. instance methods
2. static methods
3. code block inside instance methods
4. code block inside static methods

1. Synchronized instance methods


public class MyCounter {

private int count = 0;

public synchronized void add(int value){


this.count += value;
}
}
• synchronized on the instance (object) owning the method
•  each instance has its synchronized methods synchronized on a different object: the owning instance
• only 1 thread/instance can execute inside it
• more instances  1 thread at a time can execute inside it / instance
• more synchronized methods  1 thread can execute inside either of the methods

2. Synchronized static methods


• same principle: 1 thread can execute inside a static synchronized method in the same class
• > 1 static method  only 1 thread execute inside any of these methods at the same time
• if we have 2 synchronize methods: add() & subtract()
o thread A executing add()  thread B cannot execute neither add() nor subtract()until the thread A
has exited add()
• if the synchronized static methods are located in different classes, then 1 thread can execute inside the static
synchronized method of each class  1 thread / class, regardless of which static method it calls

3. Synchronized Blocks in instance methods


• used for synchronizing only a part of a method
public void add(int value){

synchronized(this){
this.count += value;
}
}
• takes an object as argument  "monitor object"
• "code is synchronized on the monitor object"
• 1 thread execution inside a Java block synchronized on the same monitor object
• 1 thread inside of 2 synchronized blocks:
o If 2nd block had been synchronized on other object than this  1 thread at a time had been able to
execute inside each method
public class MyClass {

public synchronized void log1(String msg1, String msg2){


log.writeln(msg1);
log.writeln(msg2);
}

public void log2(String msg1, String msg2){


synchronized(this){
log.writeln(msg1);
log.writeln(msg2);
}
}
}

4. Synchronized Blocks in static methods


• same principle as 3.
public class MyClass {

public static synchronized void log1(String msg1, String msg2){


log.writeln(msg1);
log.writeln(msg2);
}

public static void log2(String msg1, String msg2){


synchronized(MyClass.class){
log.writeln(msg1);
log.writeln(msg2);
}
}
}

5. Synchronized blocks in Lambda Expressions


import java.util.function.Consumer;

public class SynchronizedExample {

public static void main(String[] args) {

Consumer<String> func = (String param) -> {

synchronized(SynchronizedExample.class) {

System.out.println(
Thread.currentThread().getName() +
" step 1: " + param);

try {
Thread.sleep( (long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(
Thread.currentThread().getName() +
" step 2: " + param);
}
};

Thread thread1 = new Thread(() -> {


func.accept("Parameter");
}, "Thread 1");

Thread thread2 = new Thread(() -> {


func.accept("Parameter");
}, "Thread 2");

thread1.start();
thread2.start();
}
}
• the synchronized block is synchronized on the class object of the class containing the lambda expression
• it could've been synchronized on another object too

6. Example
public class Example {

public static void main(String[] args){

Counter counter = new Counter();

Thread threadA = new CounterThread(counter);

Thread threadB = new CounterThread(counter);

threadA.start();

threadB.start();

public class Counter{

long count = 0;

public synchronized void add(long value){


this.count += value;
}
}

public class CounterThread extends Thread{

protected Counter counter = null;

public CounterThread(Counter counter){


this.counter = counter;
}

public void run() {


for(int i=0; i<10; i++){
counter.add(i);
}
}
}
• only 1 thread at a time will be able to call the add() on the same object
• if 2 threads referenced 2 separate Counter objects  add() would've been called simultaneously

7. Synchronized and Data Visibility


• without synchronized there is no guarantee that when 1 thread changes the value of variable shared
• no guarantee about when a variable kept in a CPU register by 1 thread is "committed" to main memory, and there
is no guarantee about when other threads "refresh" a variable kept there
• with synchronized
o when a thread enters a synchronized block, it will refresh the values of all variables visible to the thread
o when a thread exits a synchronized block, all changes to variables visible to thread will be committed to
main memory

8. Synchronize and Instruction Reordering


• the java compiler & JVM are allowed to reorder instructions in another order to make them execute faster,
typically by enabling reordering instructions to be executed in parallel by the CPU
• problems may arise in this case
o if we write to a variable happening inside of a synchronous block, this was reordered to happen outside
of the synchronized block
• java synchronized keyword places some restriction on this and ensures stability

9. What objects to synchronize on


• NOT recommended: String objects, any primitive wrappers – they are already optimized by the compiler
• instead synchronize on this and new Object()

10. Limitations and Alternatives


• limitation: a single thread entering at a time
• we may need 2 threads to read a share value, and not update it  Read/Write Lock (ReadWriteLock class)
• we may want to allow N threads to enter a sync. block, not just one  Semaphore class
• limitation: they don't guarantee in what order threads waiting to enter them are granted access to the
synchronized block  implement Fairness
• 1 thread writing to a shared variable, one reading  volatile variable instead

11. Performance Overhead


• entering & exiting a synchronized block very often  overhead
• try not to have larger synchronized blocks than necessary  only synchronize the operations that really needs it
 increased parallelism

12. Synchronized Block Reentrance


• once a thread entered a sync. block it is said to "hold the lock" on the monitoring object
• if the thread calls another method which calls back to the 1st method with the sync. block inside, the thread holding
the lock can reenter the sync. block
• it is not blocked just because a thread (itself) is holding the lock, only if a different thread is holding the lock
public class MyClass {
List<String> elements = new ArrayList<String>();
public void count() {
if(elements.size() == 0) {
return 0;
}
synchronized(this) {
elements.remove();
return 1 + count(); }
}

}
• the synchronized block inside count() calls the count() recursively  enter the same synchronized block
multiple times  allowed
• however, this may lead to nested monitor lockout

13. Synchronized Blocks in Cluster Steps


• synchronized block blocks only thread within the same JVM from entering the code block
• same Java application running on multiple JVMs – in a cluster  possible for 1 thread within each JVM to enter
that synchronized block at the same time
• use other synchronization mechanism if this is the case

You might also like