Study Effective Java
Item 78: Synchronize access to mutable data
synchronized - mutual exclusion
Only one thread at one time.
Ex.
class Psudo {
int i= 0;
synchronized void inc() {
i++;
}
main() {
Psudo c = new Psudo();
new Thread() { run() { c.inc(); } }.start();
new Thread() { run() { c.inc(); } }.start();
}
}
Time Thread 1 Thread 2
clock 0 i = 0 i = 0
clock 1 i = i + 1 => i = 1
clock 2 i = i + 1 => i = 2
synchronized - mutual exclusion & visibility
Only one thread at one time.
Ex.
class Psudo {
int i= 0;
synchronized void inc() {
i++;
}
main() {
Psudo c = new Psudo();
new Thread() { run() { c.inc(); } }.start();
new Thread() { run() { c.inc(); } }.start();
}
}
Time Thread 1 Thread 2
clock 0 i = 0 i = 0
clock 1 i = i + 1 => i = 1
clock 2 i = i + 1 => i = 2
each thread entering a synchronized
method or block sees the effects of all
previous modifications that guarded by
the same lock.
without synchronized
One thread’s change may not be visible to other threads.
Ex.
class Psudo {
int i= 0;
void inc() {
i++;
}
main() {
Psudo c = new Psudo();
new Thread() { run() { c.inc(); } }.start();
new Thread() { run() { c.inc(); } }.start();
}
}
Time Thread 1 Thread 2
clock 0 i = 0 i = 0
clock 1 i = i + 1 => i = 1
clock 2 i = 0, i = i + 1 => i = 1
JLS guarantee
Java guarantees: read or write a variable is atomic, except long or double.
We should store status in one variable and prevent
synchronized block, so that we’ll get good performance!
By Java’s guarantee, we’ll get correct status!
JLS guarantee
Java guarantees: read or write a variable is atomic, except long or double.
We should store status in one variable and prevent
synchronized block, so that we’ll get good performance!
By Java’s guarantee, we’ll get correct status!
JLS guarantee
Java guarantees: read or write a variable is atomic, except long or double.
We should store status in one variable and prevent
synchronized block, so that we’ll get good performance!
By Java’s guarantee, we’ll get correct status!
Synchronization is required for reliable
communication between threads as well
as for mutual exclusion.
Memory Model: define when and how
changes made by one thread become visible
to others.
What will happen?
What will happen?
What will happen?
What will happen?
Thread 1 (Main thread) Thread 2
sleep (1000) i++
stop = true i++
i++
NO guarantee main thread will
notify thread 2 the “stop value
has changed" information
What will happen?
Thread 1 (Main thread) Thread 2
sleep (1000) i++
stop = true i++
i++
NO guarantee main thread will
notify thread 2 the “stop value
has changed" information
Memory barrier + JIT
[Wiki] A memory barrier, also known as a membar, memory fence or fence instruction, is a type of barrier
instruction that causes a central processing unit (CPU) or compiler to enforce an orderingconstraint on memory
operations issued before and after the barrier instruction. This typically means that operations issued prior to the
barrier are guaranteed to be performed before operations issued after the barrier.
[Wiki] A system implementing a JIT compiler typically continuously analyses the code being executed and
identifies parts of the code where the speedup gained from compilation or recompilation would outweigh the
overhead of compiling that code.
JIT
How to resolve? synchronized
Synchronization is not guaranteed to
work unless both read and write
operations are synchronized.
~Bloch, Joshua. Effective Java
synchronized set stop to true => value
will be shared when leaving monitoring
synchronized read stop value => make
sure program read the latest value
*In my PC, only synchronized read block is work, but book
said it’s not guaranteed in every machine.
How to resolve? volatile
The main purpose of this example is to communicate cross
threads.
By memory barrier definition of volatile, problem of this
example can be fixed by simple volatile.
No silver bullit
volatile int i = 0;
new Thread() { run() { i++; } }.start()
new Thread() { run() { i++; } }.start()
// wait until threads finish
print (i)
Output:1
No silver bullit
volatile int i = 0;
new Thread() { run() { i++; } }.start()
new Thread() { run() { i++; } }.start()
// wait until threads finish
print (i)
Output:1
No silver bullit
volatile int i = 0;
new Thread() { run() { i++; } }.start()
new Thread() { run() { i++; } }.start()
// wait until threads finish
print (i)
Output:1
i++ => i = i + 1
Threads may get same i value
No silver bullit
volatile int i = 0;
new Thread() { run() { i++; } }.start()
new Thread() { run() { i++; } }.start()
// wait until threads finish
print (i)
Output:1
i++ => i = i + 1
Threads may get same i value
Resolve: synchronized
int i = 0;
new Thread(){ run() { inc() } }.start
new Thread(){ run() { inc() } }.start
synchronized inc() { i++; }
No silver bullit
volatile int i = 0;
new Thread() { run() { i++; } }.start()
new Thread() { run() { i++; } }.start()
// wait until threads finish
print (i)
Output:1
i++ => i = i + 1
Threads may get same i value
Resolve: synchronized
int i = 0;
new Thread(){ run() { inc() } }.start
new Thread(){ run() { inc() } }.start
synchronized inc() { i++; }
Resolve: AtomicLong
AtomicLong i = new AtomicLong(0);
new Thread(){ run() { inc() } }.start
new Thread(){ run() { inc() } }.start
void inc() { i.incrementAndGet(); }
Best Practice
● Share immutable data cross threads
● Don’t share at all
Advanced
● Confine mutable data to a single thread
● understand frameworks and libraries you are using because they may
introduce threads that you are unaware of
● effectively immutable: only synchronize the act of sharing object reference
● safe publication:
○ store object in a static field as part of class initialization
○ store it in a volatile field, a final field or a field that is accessed with normal locking
○ put object in a concurrent collection
Summary
● When multiple threads share mutable data, each thread that reads or writes
the data must perform synchronization
● If you need only inter-thread communication, and not mutaual exclusion, the
volatile modifier is an acceptable form of synchronization

Study effective java item 78 synchronize access to mutable data

  • 1.
    Study Effective Java Item78: Synchronize access to mutable data
  • 2.
    synchronized - mutualexclusion Only one thread at one time. Ex. class Psudo { int i= 0; synchronized void inc() { i++; } main() { Psudo c = new Psudo(); new Thread() { run() { c.inc(); } }.start(); new Thread() { run() { c.inc(); } }.start(); } } Time Thread 1 Thread 2 clock 0 i = 0 i = 0 clock 1 i = i + 1 => i = 1 clock 2 i = i + 1 => i = 2
  • 3.
    synchronized - mutualexclusion & visibility Only one thread at one time. Ex. class Psudo { int i= 0; synchronized void inc() { i++; } main() { Psudo c = new Psudo(); new Thread() { run() { c.inc(); } }.start(); new Thread() { run() { c.inc(); } }.start(); } } Time Thread 1 Thread 2 clock 0 i = 0 i = 0 clock 1 i = i + 1 => i = 1 clock 2 i = i + 1 => i = 2 each thread entering a synchronized method or block sees the effects of all previous modifications that guarded by the same lock.
  • 4.
    without synchronized One thread’schange may not be visible to other threads. Ex. class Psudo { int i= 0; void inc() { i++; } main() { Psudo c = new Psudo(); new Thread() { run() { c.inc(); } }.start(); new Thread() { run() { c.inc(); } }.start(); } } Time Thread 1 Thread 2 clock 0 i = 0 i = 0 clock 1 i = i + 1 => i = 1 clock 2 i = 0, i = i + 1 => i = 1
  • 5.
    JLS guarantee Java guarantees:read or write a variable is atomic, except long or double. We should store status in one variable and prevent synchronized block, so that we’ll get good performance! By Java’s guarantee, we’ll get correct status!
  • 6.
    JLS guarantee Java guarantees:read or write a variable is atomic, except long or double. We should store status in one variable and prevent synchronized block, so that we’ll get good performance! By Java’s guarantee, we’ll get correct status!
  • 7.
    JLS guarantee Java guarantees:read or write a variable is atomic, except long or double. We should store status in one variable and prevent synchronized block, so that we’ll get good performance! By Java’s guarantee, we’ll get correct status!
  • 8.
    Synchronization is requiredfor reliable communication between threads as well as for mutual exclusion. Memory Model: define when and how changes made by one thread become visible to others.
  • 9.
  • 10.
  • 11.
  • 12.
    What will happen? Thread1 (Main thread) Thread 2 sleep (1000) i++ stop = true i++ i++ NO guarantee main thread will notify thread 2 the “stop value has changed" information
  • 13.
    What will happen? Thread1 (Main thread) Thread 2 sleep (1000) i++ stop = true i++ i++ NO guarantee main thread will notify thread 2 the “stop value has changed" information
  • 14.
    Memory barrier +JIT [Wiki] A memory barrier, also known as a membar, memory fence or fence instruction, is a type of barrier instruction that causes a central processing unit (CPU) or compiler to enforce an orderingconstraint on memory operations issued before and after the barrier instruction. This typically means that operations issued prior to the barrier are guaranteed to be performed before operations issued after the barrier. [Wiki] A system implementing a JIT compiler typically continuously analyses the code being executed and identifies parts of the code where the speedup gained from compilation or recompilation would outweigh the overhead of compiling that code. JIT
  • 15.
    How to resolve?synchronized Synchronization is not guaranteed to work unless both read and write operations are synchronized. ~Bloch, Joshua. Effective Java synchronized set stop to true => value will be shared when leaving monitoring synchronized read stop value => make sure program read the latest value *In my PC, only synchronized read block is work, but book said it’s not guaranteed in every machine.
  • 16.
    How to resolve?volatile The main purpose of this example is to communicate cross threads. By memory barrier definition of volatile, problem of this example can be fixed by simple volatile.
  • 17.
    No silver bullit volatileint i = 0; new Thread() { run() { i++; } }.start() new Thread() { run() { i++; } }.start() // wait until threads finish print (i) Output:1
  • 18.
    No silver bullit volatileint i = 0; new Thread() { run() { i++; } }.start() new Thread() { run() { i++; } }.start() // wait until threads finish print (i) Output:1
  • 19.
    No silver bullit volatileint i = 0; new Thread() { run() { i++; } }.start() new Thread() { run() { i++; } }.start() // wait until threads finish print (i) Output:1 i++ => i = i + 1 Threads may get same i value
  • 20.
    No silver bullit volatileint i = 0; new Thread() { run() { i++; } }.start() new Thread() { run() { i++; } }.start() // wait until threads finish print (i) Output:1 i++ => i = i + 1 Threads may get same i value Resolve: synchronized int i = 0; new Thread(){ run() { inc() } }.start new Thread(){ run() { inc() } }.start synchronized inc() { i++; }
  • 21.
    No silver bullit volatileint i = 0; new Thread() { run() { i++; } }.start() new Thread() { run() { i++; } }.start() // wait until threads finish print (i) Output:1 i++ => i = i + 1 Threads may get same i value Resolve: synchronized int i = 0; new Thread(){ run() { inc() } }.start new Thread(){ run() { inc() } }.start synchronized inc() { i++; } Resolve: AtomicLong AtomicLong i = new AtomicLong(0); new Thread(){ run() { inc() } }.start new Thread(){ run() { inc() } }.start void inc() { i.incrementAndGet(); }
  • 22.
    Best Practice ● Shareimmutable data cross threads ● Don’t share at all
  • 23.
    Advanced ● Confine mutabledata to a single thread ● understand frameworks and libraries you are using because they may introduce threads that you are unaware of ● effectively immutable: only synchronize the act of sharing object reference ● safe publication: ○ store object in a static field as part of class initialization ○ store it in a volatile field, a final field or a field that is accessed with normal locking ○ put object in a concurrent collection
  • 24.
    Summary ● When multiplethreads share mutable data, each thread that reads or writes the data must perform synchronization ● If you need only inter-thread communication, and not mutaual exclusion, the volatile modifier is an acceptable form of synchronization