SlideShare a Scribd company logo
CONCURRENCY
CONCEPTS IN JAVA
DOUGLAS Q. HAWKINS
LEAD JIT DEVELOPER
AZUL SYSTEMS
@dougqh
dougqh@gmail.com
TOPICS
NOT ABOUT
PARALLEL FORK JOIN
AKKA
EXECUTORS & FUTURES
…
CORE MEMORY MODEL
ATOMICITY
ORDERING
VISIBILITY
HISTORY & FUTURE OF THE MEMORY MODEL
TOPICS
WHO’S READ THIS?
YOU SHOULD READ THE FINE PRINT.
TLDR: “AS IF”
AS IF THERE’S ONE THREAD,
UNLESS YOU SAY OTHERWISE.
The behavior of threads, particularly
when not correctly synchronized, can
be confusing and counterintuitive.
“
“
Java 8 Language Specification
§ 17.4 pp 631
Immutable objects have a very compelling
list of positive qualities. Without question,
they are among the simplest and most robust
kinds of classes you can possibly build. When
you create immutable classes, entire
categories of problems simply disappear.
“ “
www.javapractices.com
ATOMICITYWHAT OPERATIONS ARE INDIVISIBLE?
SUCCINCT != ATOMIC
sharedX = 2L;
sharedX = 2L sharedX = -1L
set_hi sharedX, 0000 0000
set_lo sharedX, 0000 0002
set_hi sharedX, ffff ffff
set_lo sharedX, ffff ffff
thread 1 thread 2
JLS8 § 17.7 pp 658
SUCCINCT != ATOMIC
sharedX += 1;
localX = sharedX;
localX = localX + 1;
sharedX = localX;
SUCCINCT != ATOMIC
Point sharedPoint = new Point(x, y);
local1 = calloc(sizeof(Point));
local1.<init>(x, y);
Object.<init>();
this.x = x;
this.y = y;
sharedPoint = local1;
VISIBILITYWHAT CAN OTHER THREADS SEE?
NO GARBAGE VALUES
NO OUT OF “THIN AIR” VALUES
WILL SEE A ZERO-ISH VALUE
OR
AN ASSIGNED VALUE
NO *COMPLETELY* GARBAGE VALUES
TWO SEPARATE HALVES OF LONG OR DOUBLE
BUT
BOTH HALVES ARE ZERO OR ASSIGNED
ONLY ASSIGNED VALUES FOR FINALS
sharedPoint = new Point(x, y);
class Point {
final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
*
*After constructor return
JLS8 § 17.5 pp 652
NOT *ALL* VALUES ARE STORED
sharedX = 20;
sharedX = 40;
print(sharedX);
Dead Store
DATA DEPENDENCE
sharedX = 20;
sharedX = 40;
print(sharedX);
Dead Store
Data
Dependence
DATA DEPENDENCE
sharedX = 20;
sharedX = 40;
print(40);
Data
Dependence
Propagate
Data
Dead Stores
OKAY.
NOT *ALL* VALUES ARE STORED
sharedSum = 0;
for ( int x : array ) {
sharedSum += x;
}
INTERMEDIATE VALUES OPTIONAL
localSum = 0;
for ( int x : array ) {
localSum += x;
}
sharedSum = localSum;
WHAT?
THREAD PUBLISHING
METHOD PUBLISHES?
Thread.sleep NO
Thread.yield NO
Thread.join YES
Thread.isAlive YES*
* If Thread.isAlive returns false
JLS8 § 17.4 pp 636
NOT *ALL* VALUES ARE READ
xSquared = sharedX * sharedX
Can xSquared be 30?
local1 = sharedX
local2 = sharedX
xSquared = local1 * local2
NOT *ALL* VALUES ARE READ
Can xSquared be 30?
local1 = sharedX
local2 = sharedX
xSquared = local1 * local2
thread 1 thread 2
sharedX = 5;
local1 = sharedX; (5)
sharedX = 6;
local2 = sharedX; (6)
xSquared =
local1 * local2;
(30)
NOT *ALL* VALUES ARE READ
xSquared = sharedX * sharedX
local1 = sharedX
local2 = sharedX
xSquared = local1 * local2
local1 = sharedX
xSquared = local1 * local1
Redundant Load
GREAT!
IMPORTANT OPTIMIZATION
for ( int x: array ) {
… x …
}
for ( int i = 0; i < this.array.length; ++i ) {
… this.array[i] …
}
Object[] local = this.array;
for ( int i = 0; i < local.length; ++i ) {
… local[i] …
}
EXCELLENT!20+% FASTER
MAYBE NOT…
while ( !done ); local1 = !done;
while ( local1 );
Load False &
Loop Forever
To some programmers, this behavior
may seem broken. However, it should
be noted that this code is improperly
synchronized.
“
“
Java 8 Language Specification
§ 17.4 pp 638
MEMORY COHERENCE
Coherence is a guarantee that a
thread cannot see an old value for
the same memory location after
seeing a newer value.
TIME PARADOX
// sharedPoint1 might equal
// sharedPoint2
int i = sharedPoint1.x;
// another thread can change x
int j = sharedPoint2.x;
// allow old value or
// cannot optimize
int k = sharedPoint3.x;
Point
x
y
100
100
125
sharedPoint1
sharedPoint2
JLS8 § 17.4-C pp 638
The semantics of the Java programming
language allow compilers and micro-
processors to perform optimizations that
can interact with incorrectly synchronized
code in ways that can produce behaviors
that seem paradoxical.
“ “
Java 8 Language Specification
§ 17.4 pp 637
ORDERINGWHAT ORDER DOES IT RUN IN?
“PROGRAM ORDER”
sharedX = 2
sharedY = 3
if ( sharedX > 0 ) {
print(sharedX);
}
Control
Data
Data
DATA + CONTROL DEPENDENCE
DATA CONTROL DEPENDENCE+
sharedX = 2
start
end
print(x)
if ( sharedX > 0 )
true false
sharedY = 3
https://en.wikichip.org/wiki/intel/microarchitectures/kaby_lake
FETCH
RENAME & ALLOCATE
DECODE
ALLOCATION QUEUE
SCHEDULERS
ALU
VECT ALU
VECT SHIFT
VECT ADD
VECT MUL
FMA
DIV
BRANCH
ALU
FAST LEA
VECT ALU
VECT SHIFT
VECT ADD
VECT MUL
FMA
SLOW INT
SLOW LEA
ALU
FAST LEA
VECT ALU
VECT SHUFFLE
ALU & SHIFT
BRANCH
AGU
LOAD DATA
AGU
LOAD DATA
STORE DATA AGU
INTEL KABY LAKE
LOAD
BUFFER
STORE
BUFFER
INTEL KABY LAKE
https://en.wikichip.org/wiki/intel/microarchitectures/kaby_lake
FETCH
RENAME & ALLOCATE
DECODE
ALLOCATION QUEUE
SCHEDULERS
ALU
VECT ALU
VECT SHIFT
VECT ADD
VECT MUL
FMA
DIV
BRANCH
ALU
FAST LEA
VECT ALU
VECT SHIFT
VECT ADD
VECT MUL
FMA
SLOW INT
SLOW LEA
ALU
FAST LEA
VECT ALU
VECT SHUFFLE
ALU & SHIFT
BRANCH
AGU
LOAD DATA
AGU
LOAD DATA
STORE DATA AGU
LOAD
BUFFER
STORE
BUFFER
add reg0, 1 add reg1, 2
COOL.
BUT COMPLICATES
EVERYTHING.
STORE SOONER
local1 = calloc(sizeof(Point));
local1.<init>(…);
…
sharedPoint = local1;
sharedFoo = new Foo(…);
Data
Data
FREE TO REORDER
local1 = calloc(sizeof(Point));
sharedPoint = local1;
local1.<init>(…);
sharedFoo = new Foo(…);
Data
Data
Reordered!
*BROKEN* DOUBLE CHECKED LOCKING
static Singleton instance() {
if ( sharedInstance == null ) {
synchronized ( Singleton.class ) {
if ( sharedInstance == null ) {
sharedInstance = new Singleton();
}
}
}
return sharedInstance;
}
static Singleton instance() {
if ( sharedInstance == null ) {
synchronized ( Singleton.class ) {
if ( sharedInstance == null ) {
local = calloc(sizeof(Singleton));
sharedInstance = local;
local.<init>();
}
}
}
return sharedInstance;
}
sharedInstance is non-null,
but constructor hasn’t run.
PRODUCER CONSUMER
...
sharedData = ...;
sharedDone = true;
...
sharedDone = true;
sharedData = ...;
while ( !sharedDone );
print(sharedData);
Reorder!
AGAIN BLAME
HARDWARE.
RISC / ARM CISC / x86
Loads After Loads YES YES
Loads After Stores YES YES
Stores After Stores YES NO
Stores After Loads YES YES
...
sharedData = …;
store_store_fence();
sharedDone = true;
while ( !sharedDone ) {
load_load_fence();
}
print(sharedData);
TO STOP REORDERING, USE A *FENCE*
PRODUCER CONSUMER
BLAME JAVA,
TOO.
RISC / ARM CISC / x86 Java
Loads After Loads YES YES YES
Loads After Stores YES YES YES
Stores After Stores YES NO YES
Stores After Loads YES YES YES
HOW DO YOU TELL
JAVA TO NOT REORDER?
SYNCHRONIZATION ACTIONS
VOLATILE
SYNCHRONIZED
FINAL / FREEZE
UNSAFE
ATOMICS
VAR HANDLES
FINAL & FREEZE
local1 = calloc(sizeof(Point));
local1.<init>(x, y);
Object.<init>();
this.x = x;
this.y = y;
freeze();
sharedPoint = local1;
Point sharedPoint = new Point(x, y);
FINAL & FREEZE
local1 = calloc(sizeof(Point));
local1.<init>(x, y);
Object.<init>();
this.x = x;
this.y = y;
OtherThread.see(this);
freeze();
sharedPoint = local1;
Point sharedPoint = new Point(x, y);
Free to Reorder!
VOLATILE
PRE-JAVA 5 JUST ATOMICITY FOR CATEGORY 2 TYPES:
WRITE “SYNCHRONIZES WITH”
*ALL* SUBSEQUENT READS
WRITE “HAPPENS BEFORE”
*ALL* SUBSEQUENT READS
JLS8 § 17.4.4 & 17.4.5 pp 642 & 643
VOLATILE
...
volatileData = …;
volatileDone = true;
while ( !volatileDone ) {
}
print(volatileData);
PRODUCER CONSUMER
ALSO FIXES DOUBLE CHECKED LOCKING
static Singleton instance() {
if ( sharedInstance == null ) {
synchronized ( Singleton.class ) {
if ( sharedInstance == null ) {
local = calloc(sizeof(Singleton));
local.<init>();
sharedInstance = local;
}
}
}
return sharedInstance;
}
RIGHT WAY TO DO LAZY SINGLETON IN JAVA
static Singleton instance() {
return Holder.INSTANCE;
}
static class Holder {
static final class Singleton INSTANCE = new Singleton();
}
CLASS INITIALIZATION IS ALREADY LAZY.
SUCCINCT *STILL* != ATOMIC
volatileX += 1;
localX = sharedX;
localX = localX + 1;
sharedX = localX;
fullFence fullFence
loadLoadFence
storeStoreFence
acquireFence
releaseFence
NOT *ENTIRELY* ACADEMIC
UNSAFE VARHANDLES
SYNCHRONIZED
synchronized (Foo.class) {
counter += 1;
}
WAIT & NOTIFY
synchronized (lock) {
sharedData = …;
sharedDone = true;
lock.notify();
}
synchronized (lock) {
while ( !sharedDone ) {
lock.wait();
}
print(sharedData);
}
PRODUCER CONSUMER
DOESN’T PRESERVE ORDER
synchronized (lock) {
sharedData = …;
sharedDone = true;
lock.notify();
}
synchronized (lock) {
while ( !sharedDone ) {
lock.wait();
}
print(sharedData);
}
PRODUCER CONSUMER
synchronized (lock) {
sharedDone = true;
sharedData = …;
lock.notify();
}
Reorder!
SPURIOUS NOTIFICATIONS
synchronized (lock) {
while ( !sharedDone ) {
lock.wait();
}
print(sharedData);
}
*CORRECT* CONSUMER
synchronized (lock) {
if ( !sharedDone ) {
lock.wait();
}
print(sharedData);
}
*INCORRECT* CONSUMER
LOCK COARSENING
synchronized ( buffer ) {
buffer.add(x);
}
foo = bar;
synchronized ( buffer ) {
buffer.add(y);
}
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/
synchronized ( buffer ) {
buffer.add(x);
foo = bar;
buffer.add(y);
}
COMPARE & SWAP
AtomicInteger atomic = new AtomicInteger(0);
atomic.getAndIncrement();
boolean applied = false;
do {
int value = sharedVar.get();
applied = sharedVar.compareAndSet(
value, value + 1);
} while ( ! applied );
JAVA.UTIL.CONCURRENT
ConcurrentLinkedQueue
ConcurrentHashMap
A
B
C
D
LinkedTransferQueue
head tail
CONCURRENCY CAN SEEM...
BROKEN
COUNTERINTUITIVE
PARADOXICAL
DESPITE THE RULES
Immutable objects have a very compelling
list of positive qualities. Without question,
they are among the simplest and most robust
kinds of classes you can possibly build. When
you create immutable classes, entire
categories of problems simply disappear.
“ “
www.javapractices.com
REFERENCES
JAVA CURRENCY IN PRACTICE
Brian Goetz et al
JAVA MEMORY MODEL PRAGMATICS
Aleksey Shipilëv
http://virtualjug.com/java-memory-model-pragmatics/
CLOSE ENCOUNTERS OF THE JMM KIND
Aleksey Shipilëv
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/
HISTORY
JAVA’S MEMORY MODEL IS FATALLY FLAWED
Bill Pugh
http://www.cs.umd.edu/~pugh/java/broken.pdf
Bill Pugh
FIXING JAVA’S MEMORY MODEL
http://www.cs.umd.edu/~pugh/jmm.pdf
AND OF COURSE

More Related Content

What's hot (19)

PDF
Java_practical_handbook
Manusha Dilan
 
PDF
.NET Multithreading and File I/O
Jussi Pohjolainen
 
PDF
Scala to assembly
Jarek Ratajski
 
DOCX
Java practical
shweta-sharma99
 
PDF
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
julien.ponge
 
DOCX
Java PRACTICAL file
RACHIT_GUPTA
 
PDF
Java 7 LavaJUG
julien.ponge
 
PDF
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
NAVER / MusicPlatform
 
ODP
Java Generics
Carol McDonald
 
PDF
Advanced Debugging Using Java Bytecodes
Ganesh Samarthyam
 
PPT
bluespec talk
Suman Karumuri
 
DOC
Final JAVA Practical of BCA SEM-5.
Nishan Barot
 
PDF
Virtual machine and javascript engine
Duoyi Wu
 
PDF
Java Generics - by Example
Ganesh Samarthyam
 
PDF
Silicon Valley JUG: JVM Mechanics
Azul Systems, Inc.
 
PPT
About Those Python Async Concurrent Frameworks - Fantix @ OSTC 2014
Fantix King 王川
 
PDF
Software Testing - Invited Lecture at UNSW Sydney
julien.ponge
 
PDF
Apache Commons - Don\'t re-invent the wheel
tcurdt
 
PDF
Kirk Shoop, Reactive programming in C++
Sergey Platonov
 
Java_practical_handbook
Manusha Dilan
 
.NET Multithreading and File I/O
Jussi Pohjolainen
 
Scala to assembly
Jarek Ratajski
 
Java practical
shweta-sharma99
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
julien.ponge
 
Java PRACTICAL file
RACHIT_GUPTA
 
Java 7 LavaJUG
julien.ponge
 
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
NAVER / MusicPlatform
 
Java Generics
Carol McDonald
 
Advanced Debugging Using Java Bytecodes
Ganesh Samarthyam
 
bluespec talk
Suman Karumuri
 
Final JAVA Practical of BCA SEM-5.
Nishan Barot
 
Virtual machine and javascript engine
Duoyi Wu
 
Java Generics - by Example
Ganesh Samarthyam
 
Silicon Valley JUG: JVM Mechanics
Azul Systems, Inc.
 
About Those Python Async Concurrent Frameworks - Fantix @ OSTC 2014
Fantix King 王川
 
Software Testing - Invited Lecture at UNSW Sydney
julien.ponge
 
Apache Commons - Don\'t re-invent the wheel
tcurdt
 
Kirk Shoop, Reactive programming in C++
Sergey Platonov
 

Similar to Concurrency Concepts in Java (20)

PPTX
Java concurrency
Hithem Ahmed
 
PDF
Concurrency
Isaac Liao
 
PDF
Java Concurrency Gotchas
Alex Miller
 
PPTX
Effective java - concurrency
feng lee
 
PDF
Practical Introduction to Java Memory Model
Dmitry Degrave
 
PDF
Concurrency gotchas
Jitender Jain
 
PDF
Java Concurrency Gotchas
Alex Miller
 
PPTX
Concurrency in Java
Allan Huang
 
PPTX
Николай Папирный Тема: "Java memory model для простых смертных"
Ciklum Minsk
 
PPTX
The Java memory model made easy
Rafael Winterhalter
 
PDF
jvm/java - towards lock-free concurrency
Arvind Kalyan
 
PDF
Javaoneconcurrencygotchas 090610192215 Phpapp02
Tarun Kumar
 
PPT
Java Performance Tuning
Minh Hoang
 
PDF
Non-blocking synchronization — what is it and why we (don't?) need it
Alexey Fyodorov
 
PPTX
Java concurrency
Scheidt & Bachmann
 
PDF
Java Concurrency Idioms
Alex Miller
 
PPTX
Concurrency
Sandeep Chawla
 
PDF
Java Concurrency Quick Guide
Anton Shchastnyi
 
PDF
Understanding jvm gc advanced
Jean-Philippe BEMPEL
 
DOCX
Java 5 concurrency
priyank09
 
Java concurrency
Hithem Ahmed
 
Concurrency
Isaac Liao
 
Java Concurrency Gotchas
Alex Miller
 
Effective java - concurrency
feng lee
 
Practical Introduction to Java Memory Model
Dmitry Degrave
 
Concurrency gotchas
Jitender Jain
 
Java Concurrency Gotchas
Alex Miller
 
Concurrency in Java
Allan Huang
 
Николай Папирный Тема: "Java memory model для простых смертных"
Ciklum Minsk
 
The Java memory model made easy
Rafael Winterhalter
 
jvm/java - towards lock-free concurrency
Arvind Kalyan
 
Javaoneconcurrencygotchas 090610192215 Phpapp02
Tarun Kumar
 
Java Performance Tuning
Minh Hoang
 
Non-blocking synchronization — what is it and why we (don't?) need it
Alexey Fyodorov
 
Java concurrency
Scheidt & Bachmann
 
Java Concurrency Idioms
Alex Miller
 
Concurrency
Sandeep Chawla
 
Java Concurrency Quick Guide
Anton Shchastnyi
 
Understanding jvm gc advanced
Jean-Philippe BEMPEL
 
Java 5 concurrency
priyank09
 
Ad

More from Doug Hawkins (8)

PDF
ReadyNow: Azul's Unconventional "AOT"
Doug Hawkins
 
PDF
JVM Mechanics: When Does the JVM JIT & Deoptimize?
Doug Hawkins
 
PDF
Understanding Garbage Collection
Doug Hawkins
 
PDF
JVM Internals - NHJUG Jan 2012
Doug Hawkins
 
PDF
Inside Android's Dalvik VM - NEJUG Nov 2011
Doug Hawkins
 
PDF
JVM Internals - NEJUG Nov 2010
Doug Hawkins
 
KEY
Introduction to Class File Format & Byte Code
Doug Hawkins
 
PDF
JVM Internals - Garbage Collection & Runtime Optimizations
Doug Hawkins
 
ReadyNow: Azul's Unconventional "AOT"
Doug Hawkins
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
Doug Hawkins
 
Understanding Garbage Collection
Doug Hawkins
 
JVM Internals - NHJUG Jan 2012
Doug Hawkins
 
Inside Android's Dalvik VM - NEJUG Nov 2011
Doug Hawkins
 
JVM Internals - NEJUG Nov 2010
Doug Hawkins
 
Introduction to Class File Format & Byte Code
Doug Hawkins
 
JVM Internals - Garbage Collection & Runtime Optimizations
Doug Hawkins
 
Ad

Recently uploaded (20)

PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
PDF
July Patch Tuesday
Ivanti
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
July Patch Tuesday
Ivanti
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 

Concurrency Concepts in Java