Concurrency
Isaac
Agenda
● Some JVM knowledge
● Some basic concurrency concepts
● Some personal design suggestions
Reference
● Some JVM knowledge - Java Concurrency in Practice
● Some basic concurrency concepts - Clean Code
● Some personal design suggestions
Won’t be mentioned
● Practices to write concurrency program
● Patterns or anti-patterns in concurrency programming
● java.util.concurrent API example
● More detail in JVM
They are big topics, maybe other Tech Talks.
Or we can discuss with each other for interesting.
Target audience
● Java developers who don’t know about concurrency
● Your code will run in multi-threaded environment
Goal
● Be aware concurrency issue while programming
● Get some material or direction to study
● Let concurrency become a famous discussion between developers
Why Concurrency
● CPU core size maybe 8-24
But there are thousands of threads…
Currency must be a very important topic in development
What is Concurrency?
… This[Concurrency] means that even if the concurrent units
of the program, algorithm, or problem are executed
out-of-order or in partial order, the final outcome will
remain the same…
~ WIKI
What is “out-of-order”?
In this paradigm [out-of-order-execution], a processor
executes instructions in an order governed by the availability
of input data, rather than by their original order in a
program. In doing so, the processor can avoid being idle
while waiting for the preceding instruction to complete to
retrieve data for the next instruction
~ WIKI
Is it related to my java code?
Java code Reordered (Maybe)
public int test() {
int a = 1;
a++;
int b = 2;
b++;
return a+b;
}
public int test() {
int a = 1, b = 2; // load var and data
a++; // read and write
b++; // read and write
return a+b; // result is same after reordered
}
// Should be faster in a smater way…
// Most important is we don’t know the order
It seems not my business, should I care?
First of all, the program will be loaded to a CPU core to run.
CPU Core1 CPU Core2
Program in memory
Program Program
It seems not my business, should I care?
CPU only care about to run program faster and correct.
CPU don’t care about the status between threads without special command.
What will happen in main thread?
Thread A Thread B
a=1;
x=b;
b=1;
y=a;Main Thread
1. Start thread A
2. Start thread B
3. Get x and y
int x=0,y=0;
int a=0,b=0;
It seems not my business, should I care?
We can’t expect the results are always identical…
Thread A
Execution
1. a=1,x=0
2. a=1,x=1
Thread B
Execution
1. b=1,y=0
2. b=1,y=1
int x=0,y=0;
int a=0,b=0;
a=1;
x=b;
b=1;
y=a;Main Thread
1. Start thread A
2. Start thread B
3. Read x and y
Result:
1. x=0,y=1 // B finished
2. x=1,y=0 // A finished
3. x=1,y=1 // Both finished
4. x=0,y=0 // Both not finished
// and reordered
int x=0,y=0;
int a=0,b=0;
It seems not my business, should I care?
● Result 1: x=0, y=1
ThreadA ThreadB Main Thread
Code a=1;
x=b;
b=1;
y=a;
Start thread A
Start thread B
Read x and y
Cycle 1 a=1; b=1;
Cycle 2 y=a; Get x=0, y=1
Cycle 3 x=b;
It seems not my business, should I care?
● Result 2: x=1, y=0
ThreadA ThreadB Main Thread
Code a=1;
x=b;
b=1;
y=a;
Start thread A
Start thread B
Read x and y
Cycle 1 a=1; b=1;
Cycle 2 x=b; Get x=1, y=0
Cycle 3 y=a;
It seems not my business, should I care?
● Result 3: x=1, y=1
ThreadA ThreadB Main Thread
Code a=1;
x=b;
b=1;
y=a;
Start thread A
Start thread B
Read x and y
Cycle 1 a=1; b=1;
Cycle 2 x=b; y=a;
Cycle 3 Get x=1, y=1
It seems not my business, should I care?
● Result 4: x=0, y=0
ThreadA ThreadB Main Thread
Code a=1;
x=b;
b=1;
y=a;
Start thread A
Start thread B
Read x and y
Cycle 1 x=b; y=a;
Cycle 2 a=1; b=1;
Cycle 3 Get x=0, y=0
Another example more close to our daily work
class APManager {
ArrayList<AP> aps;
// online, offline AP
// register, unregister AP
}
class APStatusListener {
ArrayList<AP> aps; // set from APManager
public void infiniteCheck() {
while (true) {
for (AP ap: aps) {
if (ap.isOnline()) {...}
else {...}
}
}
}
}class AP {
String status; // online, offline
}
What problem in APStatusListener?
Another example more close to our daily work
class APManager {
ArrayList<AP> aps;
// online, offline AP
// register, unregister AP
}
class APStatusListener {
ArrayList<AP> aps; // set from APManager
public void infiniteCheck() {
while (true) {
for (AP ap: aps) {
if (ap.isOnline()) {...}
else {...}
}
}
}
}
May be always initial data.
No new AP
No AP will be removed
No status change
class AP {
String status; // online, offline
}
How to fix?
class APManager {
final CopyOnWriteArrayList<AP> aps;
// online, offline AP, change AP.status
// register, unregister AP
}
class APStatusListener {
List<AP> aps; // set from APManager
public void infiniteCheck() {
while (true) {
for (AP ap: aps) {
if (ap.isOnline()) {...}
else {...}
}
}
}
}class AP {
volatile String status; // online, offline
}
How to fix?
class APManager {
final CopyOnWriteArrayList<AP> aps;
// online, offline AP, change AP.status
// register, unregister AP
}
class APStatusListener {
List<AP> aps; // set from APManager
public void infiniteCheck() {
while (true) {
for (AP ap: aps) {
if (ap.isOnline()) {...}
else {...}
}
}
}
}
class AP {
volatile String status; // online, offline
}
final => APStatusListener will see initialized aps
CopyOnWriteArrayList => APStatusListener see modified element
(Of course you can declare aps with List<AP> and CopyOnWriteArrayList<AP> implementation)
volatile => APStatusListener see AP status change
How it works?
After JAVA 5
JVM introduce JSR-133 Java Memory Model
who defined happens-before relationship
and give final field a special meaning to make things happen.
What is happens-before relationship?
It’s rules guarantee by JVM, used to define program order.
● Each action in a thread happens before every subsequent action in that thread.
● An unlock on a monitor happens before every subsequent lock on that monitor.
● A write to a volatile field happens before every subsequent read of that volatile.
● A call to start() on a thread happens before any actions in the started thread.
● All actions in a thread happen before any other thread successfully
returns from a join() on that thread.
● If an action a happens before an action b, and b happens before an action c,
then a happens before c.
How about final field?
JSR-133 defined that after an object was properly
constructed, a final field assigned in constructor can be
visible by all threads.
How about final field in the JVM before Java 5?
The final field in old JVM has no difference between general
field except it need assign value in constructor.
Developer still need to use synchronization to ensure the
variable modification visible in all threads.
What is CopyOnWriteArrayList?
It's a thread safe ArrayList implementation in
java.util.concurrent package, introduced from Java 5. It also
leverage Java Memory Model to make sure modifications
visible to other threads.
What is CopyOnWriteArrayList?
ArrayList#add
What is CopyOnWriteArrayList?
CopyOnWriteArrayList#add
Magic in ReentrantLock
setState write value to volatile state, make sure all lock holder get latest state.
Thus don’t need synchronized tryRelease
volatile is not a siliver buttlet
● It can’t perform N++ operation with just N++..
volatile int n = 0; Thread 1 Thread 2
n++; n = 0, n = n+1 n = 0, n = n+1
Get n n = 1; n = 1
How to perform N++ atomically?
● syncrhonized (monitor lock)
int n = 0; // don’t need volatile if using synchronized
public synchronized int incremenetAndGet() {
n++;
}
How to perform N++ atomically?
● AtomicInteger#incrementAndGet
How to perform N++ atomically?
Unsafe.java
How to perform N++ atomically?
unsafe.cpp
How to perform N++ atomically?
LLVM #cmpxchg
JVM knowledge summary
● reorder
● JSR-133 Java Memory Model
● happens-before relationship
● volatile for visibility
● LLVM memory barrier
Basic concurrency concepts
● Definitions
○ Bound Resource
○ Mutual Execution
○ Starvation
○ Deadlock
○ Livelock
● Execution Models
○ Producer-Consumer
○ Writers-Readers
○ Dining-Philosophers
Bound Resource
Resources of a fixed size or number used in a concurrent environment.
Mutual Execution
Only one thread can access shared data or a shared resource at a time.
Such as Java Synchronization
Starvation
One thread or a group of threads is prohibited from proceeding for an excessively
long time or forever.
Ex. Lower priority tasks may encounter Starvation.
(Because always higher priority task)
Deadlock
Two or more threads wait for each other to finish. Each thread has a resource that
the other thread requires and neither can finish until gets the other resource.
Thread 1 Thread 2
Lock1
Lock2
acquire acquire
waitwait
Thread1 and Thread2 all need
acquire Lock1 and Lock2
to do something.
But the order is different so
deadlock may happen.
Note: Acquire and release locks in
the same order can prevent
deadlock
Livelock
A thread often acts in response to the action of another thread. If the other
thread's action is also a response to the action of another thread, then livelock
may result.
Example:
A boy and girl are dating in a restaurant. They are shy.
They order a cup of drink to share.
They try to take the drink but find another also want to drink so stop back.
And again, and again, and again...until someone stop...or never...
Execution Models
● Producer-Consumer
● Writers-Readers
● Dining-Philosophers
Producer-Consumer
● Behavior
a. Producer threads create work in a queue
b. Consumer threads acquire work from queue and complete it
● Challenge
a. Queue is the bound resource
b. Producer need wait for free space in queue
c. Consumer need wait until something in queue
d. Producer may need notify Consumer queue is not empty
e. Consumer may need notify Producer queue is empty
Producer-Consumer
● Benefit
a. Observer pattern, used to decouple model or process
b. Easy to tune thread pool
because producer and consumer have different resource occupation style
● Risk
a. Needless decoupling cause duplication and hard to define model responsibility
b. Too many decoupliing cause system too complex and waste resource
● Example
a. Message Queue
b. Thread Pool
Readers-Writers
● Behavior
○ A shared resource serves as a source of information for Readers
○ Writers may update the shared resource
● Challenge
○ Throughput issue
■ Writer prevent reader read while updating
■ Reader prevent writer write while reading
○ Stale information problem while reader allowing writer update
Readers-Writers
● Risk
○ Try to prevent read stale data
■ System load heavy
■ Useless lock
■ User don’t care
● Example
○ Cassandra
○ ElasticSearch
Dining Philosophers
● Behavior
○ Number of philosophers sitting around a circle table
○ Philosophers can’t eat when they are thinking
○ Philosophers need pick up forks on either side of them and eat
○ Philosophers can’t eat unless they hold two forks
● Challenge
○ If the philosopher to his right or left is already using
one of the forks he need, he must wait until that
philosopher finish eating and put forks back down.
○ Deadlock when everyone pick one fork and wait for another finish
○ Livelock when everyone put forks back down
and try again later
Dining Philosophers
● Challenge
○ Throughput: A philosopher need to wait other finish, although he is not thinking
● Example
○ Programmatically
■ Need hold 2 or more locks to do something
● How to solve
○ A waiter track every forks status,
philosopher need ask waiter and pick up forks
○ Prioritize forks, philosophers need follow the priority
to pick up/put back forks
○ Philosopher who has no fork get a ticket,
use a ticket to replace 2 forks to eat.
Finished philosopher give forks to who has a ticket.
Personal design suggestion
Define the model you are designing is Single-source-of-truth or not.
● Better to use Singleton when it’s Single-source-of-truth.
This model must be thread safe
● Build immutable object if it’s the copy of Single-source-of-truth.
● Be aware the copy of Single-source-of-truth maybe stale
● Single Responsibility Principle is basic
Example
Seat it self
(Single-source-of-truth)Seat list 1 Seat list 2
Manager1
Manager2
Employee1
Employee2
We are going to change seats because of re-org.
Managers ask some people for change requirements..
Example
Seat it self
(Single-source-of-truth)
Seat list 1 Seat list 2
Manager1
Manager2
Employee1
Employee2
Singleton naturally
Maybe stale.
Need compare and swap
We are going to change seats because of re-org.
Managers ask some people for change requirements..
Study Materials
● Java Concurrency in Practice
● Clean Code
● Effective Java
● JSR-133 Java Memory Model
● JSR-133 FAQ
● LLVM Atomics
Thank you~

Concurrency

  • 1.
  • 2.
    Agenda ● Some JVMknowledge ● Some basic concurrency concepts ● Some personal design suggestions
  • 3.
    Reference ● Some JVMknowledge - Java Concurrency in Practice ● Some basic concurrency concepts - Clean Code ● Some personal design suggestions
  • 4.
    Won’t be mentioned ●Practices to write concurrency program ● Patterns or anti-patterns in concurrency programming ● java.util.concurrent API example ● More detail in JVM They are big topics, maybe other Tech Talks. Or we can discuss with each other for interesting.
  • 5.
    Target audience ● Javadevelopers who don’t know about concurrency ● Your code will run in multi-threaded environment
  • 6.
    Goal ● Be awareconcurrency issue while programming ● Get some material or direction to study ● Let concurrency become a famous discussion between developers
  • 7.
    Why Concurrency ● CPUcore size maybe 8-24 But there are thousands of threads… Currency must be a very important topic in development
  • 8.
    What is Concurrency? …This[Concurrency] means that even if the concurrent units of the program, algorithm, or problem are executed out-of-order or in partial order, the final outcome will remain the same… ~ WIKI
  • 9.
    What is “out-of-order”? Inthis paradigm [out-of-order-execution], a processor executes instructions in an order governed by the availability of input data, rather than by their original order in a program. In doing so, the processor can avoid being idle while waiting for the preceding instruction to complete to retrieve data for the next instruction ~ WIKI
  • 10.
    Is it relatedto my java code? Java code Reordered (Maybe) public int test() { int a = 1; a++; int b = 2; b++; return a+b; } public int test() { int a = 1, b = 2; // load var and data a++; // read and write b++; // read and write return a+b; // result is same after reordered } // Should be faster in a smater way… // Most important is we don’t know the order
  • 11.
    It seems notmy business, should I care? First of all, the program will be loaded to a CPU core to run. CPU Core1 CPU Core2 Program in memory Program Program
  • 12.
    It seems notmy business, should I care? CPU only care about to run program faster and correct. CPU don’t care about the status between threads without special command. What will happen in main thread? Thread A Thread B a=1; x=b; b=1; y=a;Main Thread 1. Start thread A 2. Start thread B 3. Get x and y int x=0,y=0; int a=0,b=0;
  • 13.
    It seems notmy business, should I care? We can’t expect the results are always identical… Thread A Execution 1. a=1,x=0 2. a=1,x=1 Thread B Execution 1. b=1,y=0 2. b=1,y=1 int x=0,y=0; int a=0,b=0; a=1; x=b; b=1; y=a;Main Thread 1. Start thread A 2. Start thread B 3. Read x and y Result: 1. x=0,y=1 // B finished 2. x=1,y=0 // A finished 3. x=1,y=1 // Both finished 4. x=0,y=0 // Both not finished // and reordered int x=0,y=0; int a=0,b=0;
  • 14.
    It seems notmy business, should I care? ● Result 1: x=0, y=1 ThreadA ThreadB Main Thread Code a=1; x=b; b=1; y=a; Start thread A Start thread B Read x and y Cycle 1 a=1; b=1; Cycle 2 y=a; Get x=0, y=1 Cycle 3 x=b;
  • 15.
    It seems notmy business, should I care? ● Result 2: x=1, y=0 ThreadA ThreadB Main Thread Code a=1; x=b; b=1; y=a; Start thread A Start thread B Read x and y Cycle 1 a=1; b=1; Cycle 2 x=b; Get x=1, y=0 Cycle 3 y=a;
  • 16.
    It seems notmy business, should I care? ● Result 3: x=1, y=1 ThreadA ThreadB Main Thread Code a=1; x=b; b=1; y=a; Start thread A Start thread B Read x and y Cycle 1 a=1; b=1; Cycle 2 x=b; y=a; Cycle 3 Get x=1, y=1
  • 17.
    It seems notmy business, should I care? ● Result 4: x=0, y=0 ThreadA ThreadB Main Thread Code a=1; x=b; b=1; y=a; Start thread A Start thread B Read x and y Cycle 1 x=b; y=a; Cycle 2 a=1; b=1; Cycle 3 Get x=0, y=0
  • 18.
    Another example moreclose to our daily work class APManager { ArrayList<AP> aps; // online, offline AP // register, unregister AP } class APStatusListener { ArrayList<AP> aps; // set from APManager public void infiniteCheck() { while (true) { for (AP ap: aps) { if (ap.isOnline()) {...} else {...} } } } }class AP { String status; // online, offline } What problem in APStatusListener?
  • 19.
    Another example moreclose to our daily work class APManager { ArrayList<AP> aps; // online, offline AP // register, unregister AP } class APStatusListener { ArrayList<AP> aps; // set from APManager public void infiniteCheck() { while (true) { for (AP ap: aps) { if (ap.isOnline()) {...} else {...} } } } } May be always initial data. No new AP No AP will be removed No status change class AP { String status; // online, offline }
  • 20.
    How to fix? classAPManager { final CopyOnWriteArrayList<AP> aps; // online, offline AP, change AP.status // register, unregister AP } class APStatusListener { List<AP> aps; // set from APManager public void infiniteCheck() { while (true) { for (AP ap: aps) { if (ap.isOnline()) {...} else {...} } } } }class AP { volatile String status; // online, offline }
  • 21.
    How to fix? classAPManager { final CopyOnWriteArrayList<AP> aps; // online, offline AP, change AP.status // register, unregister AP } class APStatusListener { List<AP> aps; // set from APManager public void infiniteCheck() { while (true) { for (AP ap: aps) { if (ap.isOnline()) {...} else {...} } } } } class AP { volatile String status; // online, offline } final => APStatusListener will see initialized aps CopyOnWriteArrayList => APStatusListener see modified element (Of course you can declare aps with List<AP> and CopyOnWriteArrayList<AP> implementation) volatile => APStatusListener see AP status change
  • 22.
    How it works? AfterJAVA 5 JVM introduce JSR-133 Java Memory Model who defined happens-before relationship and give final field a special meaning to make things happen.
  • 23.
    What is happens-beforerelationship? It’s rules guarantee by JVM, used to define program order. ● Each action in a thread happens before every subsequent action in that thread. ● An unlock on a monitor happens before every subsequent lock on that monitor. ● A write to a volatile field happens before every subsequent read of that volatile. ● A call to start() on a thread happens before any actions in the started thread. ● All actions in a thread happen before any other thread successfully returns from a join() on that thread. ● If an action a happens before an action b, and b happens before an action c, then a happens before c.
  • 24.
    How about finalfield? JSR-133 defined that after an object was properly constructed, a final field assigned in constructor can be visible by all threads.
  • 25.
    How about finalfield in the JVM before Java 5? The final field in old JVM has no difference between general field except it need assign value in constructor. Developer still need to use synchronization to ensure the variable modification visible in all threads.
  • 26.
    What is CopyOnWriteArrayList? It'sa thread safe ArrayList implementation in java.util.concurrent package, introduced from Java 5. It also leverage Java Memory Model to make sure modifications visible to other threads.
  • 27.
  • 28.
  • 29.
    Magic in ReentrantLock setStatewrite value to volatile state, make sure all lock holder get latest state. Thus don’t need synchronized tryRelease
  • 30.
    volatile is nota siliver buttlet ● It can’t perform N++ operation with just N++.. volatile int n = 0; Thread 1 Thread 2 n++; n = 0, n = n+1 n = 0, n = n+1 Get n n = 1; n = 1
  • 31.
    How to performN++ atomically? ● syncrhonized (monitor lock) int n = 0; // don’t need volatile if using synchronized public synchronized int incremenetAndGet() { n++; }
  • 32.
    How to performN++ atomically? ● AtomicInteger#incrementAndGet
  • 33.
    How to performN++ atomically? Unsafe.java
  • 34.
    How to performN++ atomically? unsafe.cpp
  • 35.
    How to performN++ atomically? LLVM #cmpxchg
  • 36.
    JVM knowledge summary ●reorder ● JSR-133 Java Memory Model ● happens-before relationship ● volatile for visibility ● LLVM memory barrier
  • 37.
    Basic concurrency concepts ●Definitions ○ Bound Resource ○ Mutual Execution ○ Starvation ○ Deadlock ○ Livelock ● Execution Models ○ Producer-Consumer ○ Writers-Readers ○ Dining-Philosophers
  • 38.
    Bound Resource Resources ofa fixed size or number used in a concurrent environment.
  • 39.
    Mutual Execution Only onethread can access shared data or a shared resource at a time. Such as Java Synchronization
  • 40.
    Starvation One thread ora group of threads is prohibited from proceeding for an excessively long time or forever. Ex. Lower priority tasks may encounter Starvation. (Because always higher priority task)
  • 41.
    Deadlock Two or morethreads wait for each other to finish. Each thread has a resource that the other thread requires and neither can finish until gets the other resource. Thread 1 Thread 2 Lock1 Lock2 acquire acquire waitwait Thread1 and Thread2 all need acquire Lock1 and Lock2 to do something. But the order is different so deadlock may happen. Note: Acquire and release locks in the same order can prevent deadlock
  • 42.
    Livelock A thread oftenacts in response to the action of another thread. If the other thread's action is also a response to the action of another thread, then livelock may result. Example: A boy and girl are dating in a restaurant. They are shy. They order a cup of drink to share. They try to take the drink but find another also want to drink so stop back. And again, and again, and again...until someone stop...or never...
  • 43.
    Execution Models ● Producer-Consumer ●Writers-Readers ● Dining-Philosophers
  • 44.
    Producer-Consumer ● Behavior a. Producerthreads create work in a queue b. Consumer threads acquire work from queue and complete it ● Challenge a. Queue is the bound resource b. Producer need wait for free space in queue c. Consumer need wait until something in queue d. Producer may need notify Consumer queue is not empty e. Consumer may need notify Producer queue is empty
  • 45.
    Producer-Consumer ● Benefit a. Observerpattern, used to decouple model or process b. Easy to tune thread pool because producer and consumer have different resource occupation style ● Risk a. Needless decoupling cause duplication and hard to define model responsibility b. Too many decoupliing cause system too complex and waste resource ● Example a. Message Queue b. Thread Pool
  • 46.
    Readers-Writers ● Behavior ○ Ashared resource serves as a source of information for Readers ○ Writers may update the shared resource ● Challenge ○ Throughput issue ■ Writer prevent reader read while updating ■ Reader prevent writer write while reading ○ Stale information problem while reader allowing writer update
  • 47.
    Readers-Writers ● Risk ○ Tryto prevent read stale data ■ System load heavy ■ Useless lock ■ User don’t care ● Example ○ Cassandra ○ ElasticSearch
  • 48.
    Dining Philosophers ● Behavior ○Number of philosophers sitting around a circle table ○ Philosophers can’t eat when they are thinking ○ Philosophers need pick up forks on either side of them and eat ○ Philosophers can’t eat unless they hold two forks ● Challenge ○ If the philosopher to his right or left is already using one of the forks he need, he must wait until that philosopher finish eating and put forks back down. ○ Deadlock when everyone pick one fork and wait for another finish ○ Livelock when everyone put forks back down and try again later
  • 49.
    Dining Philosophers ● Challenge ○Throughput: A philosopher need to wait other finish, although he is not thinking ● Example ○ Programmatically ■ Need hold 2 or more locks to do something ● How to solve ○ A waiter track every forks status, philosopher need ask waiter and pick up forks ○ Prioritize forks, philosophers need follow the priority to pick up/put back forks ○ Philosopher who has no fork get a ticket, use a ticket to replace 2 forks to eat. Finished philosopher give forks to who has a ticket.
  • 50.
    Personal design suggestion Definethe model you are designing is Single-source-of-truth or not. ● Better to use Singleton when it’s Single-source-of-truth. This model must be thread safe ● Build immutable object if it’s the copy of Single-source-of-truth. ● Be aware the copy of Single-source-of-truth maybe stale ● Single Responsibility Principle is basic
  • 51.
    Example Seat it self (Single-source-of-truth)Seatlist 1 Seat list 2 Manager1 Manager2 Employee1 Employee2 We are going to change seats because of re-org. Managers ask some people for change requirements..
  • 52.
    Example Seat it self (Single-source-of-truth) Seatlist 1 Seat list 2 Manager1 Manager2 Employee1 Employee2 Singleton naturally Maybe stale. Need compare and swap We are going to change seats because of re-org. Managers ask some people for change requirements..
  • 53.
    Study Materials ● JavaConcurrency in Practice ● Clean Code ● Effective Java ● JSR-133 Java Memory Model ● JSR-133 FAQ ● LLVM Atomics
  • 54.