SlideShare a Scribd company logo
1 of 44
Java Memory Model
   The enigma of Java




       James Perry
About Me

Software Engineer at Barclays Capital
http://www.natureinspiredcode.com
http://github.com/natureinspired/8queen-ea
g-graphs
Twitter: @nature_inspired
JMM in a Nutshell

JMM is a universal contract for how threads
interact with memory in Java programs.
Happens-Before ordering: "official" reasoning
for thread interaction.
synchronized provides mutual exclusion and
memory visibility.
volatile provides atomic memory visibility.
public class SleepyThreadDemo {

    private static boolean awake;

    public static void main(String[] args) throws InterruptedException {
      Thread sleepyThread = new Thread(new Runnable() {
          public void run() {
            int zCount = 0;
            while(!awake) {
               zCount++;
            }
          }
      });
      sleepyThread.start();

        TimeUnit.SECONDS.sleep(1);
        awake = true;
    }

}
public class SleepyThreadDemo {

  private static boolean awake;

  public static void main(String[] args) throws InterruptedException {
    Thread sleepyThread = new Thread(new Runnable() {
        public void run() {
          int zCount = 0;
          if (!awake) {
              while(true) {
                zCount++;
              }
          }
        }
    });
    sleepyThread.start();

      TimeUnit.SECONDS.sleep(1);
      awake = true;
  }
Causality

    Cause
       Symmetric Multiprocessing (SMP)
       Memory Ordering
       Memory Barriers
       Compiler Optimisation
    Effect
       History
       Objectives
       Happens-Before Ordering
       Concurrency Constructs
Symmetrical Multiprocessing




          Memory Contention
          Cache Coherency
Symmetrical Multiprocessing
      T1       T2       Tn
Symmetrical Multiprocessing
     foo = 42        foo = 1        foo = 12




            public static int foo = 1
Symmetrical Multiprocessing
     foo = 42       foo = 42        foo = 42




            public static int foo = 42
Memory Ordering

                 1. CPU 0 executes a=1.
int a = 1;       2. CPU 0 looks “a” up in the cache, and finds
int b = a + 1;      that it is missing.
assert(b == 2)   3. CPU 0 therefore sends a “read invalidate” mes-
                    sage in order to get exclusive ownership of the
                    cache line containing “a”.
                 4. CPU 0 records the store to “a” in its store
                    buffer.
                 5. CPU 1 receives the “read invalidate” message,
                    and responds by transmitting the cache line
                    and removing that cacheline from its cache.
Memory Ordering
                 6. CPU 0 starts executing the b=a+1.
int a = 1;
                 7. CPU 0 receives the cache line from CPU 1,
int b = a + 1;   which still has a value of zero for “a”.
assert(b == 2)   8. CPU 0 loads “a” from its cache, finding the value
                 zero.
                 9. CPU 0 applies the entry from its store queue to
                 the newly arrived cache line, setting the value of “a”
                 in its cache to one.
                 10. CPU 0 adds one to the value zero loaded for
                 “a” above, and stores it into the cache line
                 containing “b” (which we will assume is already
                 owned by CPU 0).
                 11. CPU 0 executes assert(b==2), which fails.
Memory Ordering                1. CPU 0 executes a=1. The cache line
                                  is not in CPU 0’s cache, so CPU 0
                                  places the new value of “a” in its store
 @Singleton                       buffer and transmits a “read invalidate”
 class FooBar {                   message.
                               2. CPU 1 executes while(b==0)continue,
     private int a, b;            but the cache line containing “b” is not
                                  in its cache. It therefore transmits a
                                  “read” message.
     public void foo() {       3. CPU 0 executes b=1. It already owns
       a = 1;                     this cache line, so it stores the new
       b = 1;                     value of “b” in its cache line.
     }                         4. CPU 0 receives the “read” message,
                                  and transmits the cache line
     public void bar() {          containing the now-updated value of
       while(b==0) continue;      “b” to CPU 1, also marking the line as
       assert(a==1);              “shared” in its own cache.
     }

 }
Memory Ordering                5. CPU 1 receives the cache line
                               containing “b” and installs it in its cache.
                               6. CPU 1 can now finish executing while
                               (b==0) continue, and since it finds that
 @Singleton                    the value of “b” is 1, it proceeds to the
 class FooBar {                next statement.
                               7. CPU 1 executes the assert(a==1),
     private int a, b;         and, since CPU 1 is working with the old
                               value of “a”, this assertion fails.
     public void foo() {       8. CPU 1 receives the “read invalidate”
       a = 1;                  message, and transmits the cache line
                               containing “a” to CPU 0 and invalidates
       b = 1;
                               this cache line from its own cache. But it
     }                         is too late.
                               9. CPU 0 receives the cache line
     public void bar() {       containing “a” and applies the buffered
       while(b==0) continue;   store just in time to fall victim to CPU 1’s
       assert(a==1);           failed assertion.
     }

 }
1. CPU 0 executes a=1. The cache line is not in
Memory Ordering                   CPU 0’s cache, so CPU 0 places the new
                                  value of “a” in its store buffer and transmits a
                                  “read invalidate” message.
 @Singleton                    2. CPU 1 executes while(b==0)continue, but
 class FooBar {                   the cache line containing “b” is not in its
                                  cache. It therefore transmits a “read”
                                  message.
     private int a, b;         3. CPU 0 executes fence(), and marks all
                                  current store-buffer entries (namely, the
                                  a=1).
     public void foo() {       4. CPU 0 executes b=1. It already owns this
       a = 1;                     cache line, but there is a marked entry in the
       fence();                   store buffer. Therefore, rather than store the
                                  new value of “b” in the cache line, it instead
       b = 1;                     places it in the store buffer (but in an
     }                            unmarked entry).
                               5. CPU 0 receives the “read” message, and
                                  trans- mits the cache line containing the
     public void bar() {          original value of “b” to CPU 1. It also marks
       while(b==0) continue;      its own copy of this cache line as “shared”.
       assert(a==1);           6. CPU 1 receives the cache line containing “b”
                                  and installs it in its cache.
     }                         7. CPU 1 can now finish executing while(b==0)
                                  continue, but since it finds that the value of
 }                                'b' i still 0, it repeats the while statement. The
                                  new value of 'b' is safely hidden in CPU 0's
                                  store buffer.
Memory Fencing                 8. CPU 1 receives the “read invalidate”
                               message, and transmits the cache line
                               containing 'a' to CPU 0 and invalidates this
 @Singleton                    cache line from its own cache.
 class FooBar {                9. CPU 0 receives the cache line containing
                               'a' and applies the buffered store.
                               10. Since the store to 'a' was the only entry in
     private int a, b;         the store buffer that was marked by fence(),
                               CPU 0 can also store the new value 'b' -
                               expect for the fact that the cache line
     public void foo() {       containing 'b' is now in 'shared' state.
       a = 1;                  11. CPU 0 therefore sends an 'invalidate
       fence();                message to CPU 1'.
                               12. CPU 1 receives the 'invalidate' message,
       b = 1;                  invalidates the cache line containing 'b' from
     }                         its cache, and sends an 'acknowledgement'
                               message to CPU 0.
                               13. CPU 1 executes while(b==0)continue,
     public void bar() {       but the cache line containing 'b' is not in
       while(b==0) continue;   cache. It therefore transmits a 'read' message
       assert(a==1);           to CPU 0.
     }

 }
Memory Fencing                 14. CPU 0 receives the 'acknowledgement'
                               message, and puts the cache line containing 'b'
 @Singleton                    into the 'exclusive' state. CPU 0 now stores the
                               new value of 'b' into the cache line.
 class FooBar {                15. CPU 0 receives the 'read' message, and
                               transmits the cache line containing the original
     private int a, b;         value of 'b' to CPU 1. It also marks its own copy
                               of this cache as 'shared'.
                               16. CPU 1 receives the cache line containing 'b'
     public void foo() {       and installs it in its cache.
       a = 1;                  17. CPU 1 can now finish executing while
                               (b==0)continue and since it finds that the value
       fence();                of 'b' is 1, it proceeds to the next statement.
       b = 1;                  18. CPU 1 executes the assert(a==1) but the
     }                         cache line containing 'a' is no longer in its
                               cache. Once it gets this cache from CPU 0, it
                               will be working with the up-to-date value of 'a',
     public void bar() {       thus assertion passes.
       while(b==0) continue;
       assert(a==1);
     }

 }
Compiler Optimisations
Loop Fusion

int i = 0, size = 100;
int[] a = new int[size], b = new int[size];

for (i = 0; i < size; i++) {
   a[i] = 1;
}
for (i = 0; i < size; i++) {
   b[i] = 2;
}
Compiler Optimisations
Loop Fusion

int i = 0, size = 100;
int[] a = new int[size], b = new int[size];

for (i = 0; i < size; i++) {
   a[i] = 1;
   b[i] = 2;
}
Compiler Optimisations
Loop Fission

int i = 0, size = 100;
int[] a = new int[size], b = new int[size];

for (i = 0; i < size; i++) {
   a[i] = 1;
   b[i] = 2;
}
Compiler Optimisations
Loop Fission

int i = 0, size = 100;
int[] a = new int[size], b = new int[size];

for (i = 0; i < size; i++) {
   a[i] = 1;
}
for (i = 0; i < size; i++) {
   b[i] = 2;
}
Compiler Optimisations
Lock Coarsening

BigDecimal total = account.getTotal();
synchronized(account) {
  BigDecimal newTotal = total.multiply(INTEREST_RATE);
  account.setTotal(newTotal);
}
Compiler Optimisations
Lock Coarsening

synchronized(account) {
  BigDecimal total = account.getTotal();
  BigDecimal newTotal = total.multiply(INTEREST_RATE);
  account.setTotal(newTotal);
}
Compiler Optimisations
Lock Elision

public static void main(String... args) {
  ConcurrentMap<String,Integer> map;
  map = new ConcurrentHashMap<String, Integer>();
  map.put("one", Integer.valueOf(1));
  map.put("two", Integer.valueOf(2));
  map.put("three", Integer.valueOf(3));
}
Compiler Optimisations
Lock Elision

public class Foo implements Runnable {
  public void run() {
     synchronized(new Object()) {
        //Do something
     }
  }
}
What is a Memory Model

 A model to describe thread interaction with memory.
 Multiprocessors have different memory models.
    Inconsistently weak
 Enables to instruct memory fencing.
 Helps to write date race free
 Preserving program order.
Java Memory Model

 A Memory Model for consistent thread behaviour with
 memory for all CPU architectures
     Alpha
     RISC
     PowerPC
     x86
     AMD64
 Pioneering
 Influential
Java Memory Model

 History
    Initially broken
         volatile was not very volatile
         final was not very final
 Developers originally worked around locks.
 Huge open research area
 Constantly finding new ways to improve the JMM.
 People looking to go towards different ways of reasoning.
Java Memory Model

Goals

1. Allow as many compiler and hardware optimisations as
possible.

2. Provide balance between optimisations and correctly
synchronised code.

3. Provide developers to write and reason about multithreaded
code.
Happens-Before Ordering
Java's synchronized keyword
public class BankAccount {

    private BigDecimal total = new BigDecimal(0);

    public BigDecimal withdraw(BigDecimal amount) {
      total = total.minus(amount);
      return total;
    }

    public BigDecimal deposit(BigDecimal amount) {
      total = total.add(amount);
      return total;
    }

    public BigDecimal total() { return total; }

}
Symmetrical Multiprocessing
    deposit(200)   withdraw(100) total() == 0
       T1              T2            T3




   BankAccount account = new BankAccount();
Java's synchronized keyword
public class BankAccount {

    private BigDecimal total = new BigDecimal(0);

    public synchronized BigDecimal withdraw(BigDecimal amount) {
      total = total.minus(amount);
      return total;
    }

    public synchronized BigDecimal deposit(BigDecimal amount) {
      total = total.add(amount);
      return total;
    }

    public synchronized BigDecimal total() {return total;}

}
Symmetrical Multiprocessing
    deposit(200)   withdraw(100) total() == 100
       T1              T2            T3




   BankAccount account = new BankAccount();
Java's volatile keyword

@Singleton
class FooFactory {

  private Foo foo;

  public Foo getFoo() {
    if (foo == null) {
        synchronized(this) {
           if (foo == null) {
              foo = new Foo("bar");
          }
        }
    }
    return foo;
Java's volatile keyword
class Foo {

    private String name;

    public Foo(String name) {
      setName(name);
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getName() {
      return name;
    }

}
Symmetrical Multiprocessing
    new Foo()   name == null   name == "bar"




                foo = "bar"
Java's volatile keyword

@Singleton
class FooFactory {

  private volatile Foo foo;

  public Foo getFoo() {
    if (foo == null) {
        synchronized(this) {
           if (foo == null) {
              foo = new Foo();
           }
        }
    }
    return foo;
Symmetrical Multiprocessing
  new Foo("bar")   name == "bar"   name == "bar"




                   name == "bar"
Java's volatile keyword

@ThreadSafe
class FooFactory {

    private static class FooHelper {
       public static Foo foo = new Foo();
    }

    public static Foo getFoo() {
      return FooHelper.foo;
    }

}
Java's final keyword

class MeaningOfLife {

    private final int answer;

    public MeaningOfLife(int answer){
      this.answer = answer;
    }

    public int answer() {
      return this.answer;
    }

}
Final
   int answer = 42   int answer = 42   int answer = 42




   MeaningOfLife life = new MeaningOfLife(42);
Summary

Memory ordering can change the program
order of multithreaded code.
Memory barriers inhibits optimisations for
correct synchronisation.
Java Concurrency Constructs: ensures mutual
exclusion and memory visibility
Happens-Before ordering: any subsequent
lock acquisitions will see changes made by
previous lock releases.

More Related Content

Viewers also liked

Java gc
Java gcJava gc
Java gc
Niit
 
Николай Папирный Тема: "Java memory model для простых смертных"
Николай Папирный Тема: "Java memory model для простых смертных"Николай Папирный Тема: "Java memory model для простых смертных"
Николай Папирный Тема: "Java memory model для простых смертных"
Ciklum Minsk
 
GC Tuning in the HotSpot Java VM - a FISL 10 Presentation
GC Tuning in the HotSpot Java VM - a FISL 10 PresentationGC Tuning in the HotSpot Java VM - a FISL 10 Presentation
GC Tuning in the HotSpot Java VM - a FISL 10 Presentation
Ludovic Poitou
 

Viewers also liked (20)

The Java Memory Model
The Java Memory ModelThe Java Memory Model
The Java Memory Model
 
The Java memory model made easy
The Java memory model made easyThe Java memory model made easy
The Java memory model made easy
 
Java GC - Pause tuning
Java GC - Pause tuningJava GC - Pause tuning
Java GC - Pause tuning
 
Java gc
Java gcJava gc
Java gc
 
[BGOUG] Java GC - Friend or Foe
[BGOUG] Java GC - Friend or Foe[BGOUG] Java GC - Friend or Foe
[BGOUG] Java GC - Friend or Foe
 
Java Memory Model
Java Memory ModelJava Memory Model
Java Memory Model
 
Вячеслав Блинов «Java Garbage Collection: A Performance Impact»
Вячеслав Блинов «Java Garbage Collection: A Performance Impact»Вячеслав Блинов «Java Garbage Collection: A Performance Impact»
Вячеслав Блинов «Java Garbage Collection: A Performance Impact»
 
Java Garbage Collection(GC)- Study
Java Garbage Collection(GC)- StudyJava Garbage Collection(GC)- Study
Java Garbage Collection(GC)- Study
 
Java concurrency
Java concurrencyJava concurrency
Java concurrency
 
Николай Папирный Тема: "Java memory model для простых смертных"
Николай Папирный Тема: "Java memory model для простых смертных"Николай Папирный Тема: "Java memory model для простых смертных"
Николай Папирный Тема: "Java memory model для простых смертных"
 
Java Memory Model
Java Memory ModelJava Memory Model
Java Memory Model
 
Java Memory Consistency Model - concepts and context
Java Memory Consistency Model - concepts and contextJava Memory Consistency Model - concepts and context
Java Memory Consistency Model - concepts and context
 
Java gc and JVM optimization
Java gc  and JVM optimizationJava gc  and JVM optimization
Java gc and JVM optimization
 
What you need to know about GC
What you need to know about GCWhat you need to know about GC
What you need to know about GC
 
Java memory model
Java memory modelJava memory model
Java memory model
 
Java GC, Off-heap workshop
Java GC, Off-heap workshopJava GC, Off-heap workshop
Java GC, Off-heap workshop
 
How long can you afford to Stop The World?
How long can you afford to Stop The World?How long can you afford to Stop The World?
How long can you afford to Stop The World?
 
JVM及其调优
JVM及其调优JVM及其调优
JVM及其调优
 
Tuning Java GC to resolve performance issues
Tuning Java GC to resolve performance issuesTuning Java GC to resolve performance issues
Tuning Java GC to resolve performance issues
 
GC Tuning in the HotSpot Java VM - a FISL 10 Presentation
GC Tuning in the HotSpot Java VM - a FISL 10 PresentationGC Tuning in the HotSpot Java VM - a FISL 10 Presentation
GC Tuning in the HotSpot Java VM - a FISL 10 Presentation
 

More from Skills Matter

Oscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheimOscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheim
Skills Matter
 
Russ miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-diveRuss miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-dive
Skills Matter
 
I went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_tI went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_t
Skills Matter
 

More from Skills Matter (20)

5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard Lawrence5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard Lawrence
 
Patterns for slick database applications
Patterns for slick database applicationsPatterns for slick database applications
Patterns for slick database applications
 
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvmScala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
 
Oscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheimOscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheim
 
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
 
Cukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberlCukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberl
 
Cukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.jsCukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.js
 
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
 
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
 
Progressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source worldProgressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source world
 
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
 
Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#
 
A poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testingA poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testing
 
Russ miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-diveRuss miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-dive
 
Serendipity-neo4j
Serendipity-neo4jSerendipity-neo4j
Serendipity-neo4j
 
Simon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelismSimon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelism
 
Plug 20110217
Plug   20110217Plug   20110217
Plug 20110217
 
Lug presentation
Lug presentationLug presentation
Lug presentation
 
I went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_tI went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_t
 
Plug saiku
Plug   saikuPlug   saiku
Plug saiku
 

Recently uploaded

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Recently uploaded (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 

Java Memory Model

  • 1. Java Memory Model The enigma of Java James Perry
  • 2. About Me Software Engineer at Barclays Capital http://www.natureinspiredcode.com http://github.com/natureinspired/8queen-ea g-graphs Twitter: @nature_inspired
  • 3. JMM in a Nutshell JMM is a universal contract for how threads interact with memory in Java programs. Happens-Before ordering: "official" reasoning for thread interaction. synchronized provides mutual exclusion and memory visibility. volatile provides atomic memory visibility.
  • 4. public class SleepyThreadDemo { private static boolean awake; public static void main(String[] args) throws InterruptedException { Thread sleepyThread = new Thread(new Runnable() { public void run() { int zCount = 0; while(!awake) { zCount++; } } }); sleepyThread.start(); TimeUnit.SECONDS.sleep(1); awake = true; } }
  • 5. public class SleepyThreadDemo { private static boolean awake; public static void main(String[] args) throws InterruptedException { Thread sleepyThread = new Thread(new Runnable() { public void run() { int zCount = 0; if (!awake) { while(true) { zCount++; } } } }); sleepyThread.start(); TimeUnit.SECONDS.sleep(1); awake = true; }
  • 6. Causality Cause Symmetric Multiprocessing (SMP) Memory Ordering Memory Barriers Compiler Optimisation Effect History Objectives Happens-Before Ordering Concurrency Constructs
  • 7. Symmetrical Multiprocessing Memory Contention Cache Coherency
  • 9. Symmetrical Multiprocessing foo = 42 foo = 1 foo = 12 public static int foo = 1
  • 10. Symmetrical Multiprocessing foo = 42 foo = 42 foo = 42 public static int foo = 42
  • 11.
  • 12. Memory Ordering 1. CPU 0 executes a=1. int a = 1; 2. CPU 0 looks “a” up in the cache, and finds int b = a + 1; that it is missing. assert(b == 2) 3. CPU 0 therefore sends a “read invalidate” mes- sage in order to get exclusive ownership of the cache line containing “a”. 4. CPU 0 records the store to “a” in its store buffer. 5. CPU 1 receives the “read invalidate” message, and responds by transmitting the cache line and removing that cacheline from its cache.
  • 13. Memory Ordering 6. CPU 0 starts executing the b=a+1. int a = 1; 7. CPU 0 receives the cache line from CPU 1, int b = a + 1; which still has a value of zero for “a”. assert(b == 2) 8. CPU 0 loads “a” from its cache, finding the value zero. 9. CPU 0 applies the entry from its store queue to the newly arrived cache line, setting the value of “a” in its cache to one. 10. CPU 0 adds one to the value zero loaded for “a” above, and stores it into the cache line containing “b” (which we will assume is already owned by CPU 0). 11. CPU 0 executes assert(b==2), which fails.
  • 14. Memory Ordering 1. CPU 0 executes a=1. The cache line is not in CPU 0’s cache, so CPU 0 places the new value of “a” in its store @Singleton buffer and transmits a “read invalidate” class FooBar { message. 2. CPU 1 executes while(b==0)continue, private int a, b; but the cache line containing “b” is not in its cache. It therefore transmits a “read” message. public void foo() { 3. CPU 0 executes b=1. It already owns a = 1; this cache line, so it stores the new b = 1; value of “b” in its cache line. } 4. CPU 0 receives the “read” message, and transmits the cache line public void bar() { containing the now-updated value of while(b==0) continue; “b” to CPU 1, also marking the line as assert(a==1); “shared” in its own cache. } }
  • 15. Memory Ordering 5. CPU 1 receives the cache line containing “b” and installs it in its cache. 6. CPU 1 can now finish executing while (b==0) continue, and since it finds that @Singleton the value of “b” is 1, it proceeds to the class FooBar { next statement. 7. CPU 1 executes the assert(a==1), private int a, b; and, since CPU 1 is working with the old value of “a”, this assertion fails. public void foo() { 8. CPU 1 receives the “read invalidate” a = 1; message, and transmits the cache line containing “a” to CPU 0 and invalidates b = 1; this cache line from its own cache. But it } is too late. 9. CPU 0 receives the cache line public void bar() { containing “a” and applies the buffered while(b==0) continue; store just in time to fall victim to CPU 1’s assert(a==1); failed assertion. } }
  • 16. 1. CPU 0 executes a=1. The cache line is not in Memory Ordering CPU 0’s cache, so CPU 0 places the new value of “a” in its store buffer and transmits a “read invalidate” message. @Singleton 2. CPU 1 executes while(b==0)continue, but class FooBar { the cache line containing “b” is not in its cache. It therefore transmits a “read” message. private int a, b; 3. CPU 0 executes fence(), and marks all current store-buffer entries (namely, the a=1). public void foo() { 4. CPU 0 executes b=1. It already owns this a = 1; cache line, but there is a marked entry in the fence(); store buffer. Therefore, rather than store the new value of “b” in the cache line, it instead b = 1; places it in the store buffer (but in an } unmarked entry). 5. CPU 0 receives the “read” message, and trans- mits the cache line containing the public void bar() { original value of “b” to CPU 1. It also marks while(b==0) continue; its own copy of this cache line as “shared”. assert(a==1); 6. CPU 1 receives the cache line containing “b” and installs it in its cache. } 7. CPU 1 can now finish executing while(b==0) continue, but since it finds that the value of } 'b' i still 0, it repeats the while statement. The new value of 'b' is safely hidden in CPU 0's store buffer.
  • 17. Memory Fencing 8. CPU 1 receives the “read invalidate” message, and transmits the cache line containing 'a' to CPU 0 and invalidates this @Singleton cache line from its own cache. class FooBar { 9. CPU 0 receives the cache line containing 'a' and applies the buffered store. 10. Since the store to 'a' was the only entry in private int a, b; the store buffer that was marked by fence(), CPU 0 can also store the new value 'b' - expect for the fact that the cache line public void foo() { containing 'b' is now in 'shared' state. a = 1; 11. CPU 0 therefore sends an 'invalidate fence(); message to CPU 1'. 12. CPU 1 receives the 'invalidate' message, b = 1; invalidates the cache line containing 'b' from } its cache, and sends an 'acknowledgement' message to CPU 0. 13. CPU 1 executes while(b==0)continue, public void bar() { but the cache line containing 'b' is not in while(b==0) continue; cache. It therefore transmits a 'read' message assert(a==1); to CPU 0. } }
  • 18. Memory Fencing 14. CPU 0 receives the 'acknowledgement' message, and puts the cache line containing 'b' @Singleton into the 'exclusive' state. CPU 0 now stores the new value of 'b' into the cache line. class FooBar { 15. CPU 0 receives the 'read' message, and transmits the cache line containing the original private int a, b; value of 'b' to CPU 1. It also marks its own copy of this cache as 'shared'. 16. CPU 1 receives the cache line containing 'b' public void foo() { and installs it in its cache. a = 1; 17. CPU 1 can now finish executing while (b==0)continue and since it finds that the value fence(); of 'b' is 1, it proceeds to the next statement. b = 1; 18. CPU 1 executes the assert(a==1) but the } cache line containing 'a' is no longer in its cache. Once it gets this cache from CPU 0, it will be working with the up-to-date value of 'a', public void bar() { thus assertion passes. while(b==0) continue; assert(a==1); } }
  • 19. Compiler Optimisations Loop Fusion int i = 0, size = 100; int[] a = new int[size], b = new int[size]; for (i = 0; i < size; i++) { a[i] = 1; } for (i = 0; i < size; i++) { b[i] = 2; }
  • 20. Compiler Optimisations Loop Fusion int i = 0, size = 100; int[] a = new int[size], b = new int[size]; for (i = 0; i < size; i++) { a[i] = 1; b[i] = 2; }
  • 21. Compiler Optimisations Loop Fission int i = 0, size = 100; int[] a = new int[size], b = new int[size]; for (i = 0; i < size; i++) { a[i] = 1; b[i] = 2; }
  • 22. Compiler Optimisations Loop Fission int i = 0, size = 100; int[] a = new int[size], b = new int[size]; for (i = 0; i < size; i++) { a[i] = 1; } for (i = 0; i < size; i++) { b[i] = 2; }
  • 23. Compiler Optimisations Lock Coarsening BigDecimal total = account.getTotal(); synchronized(account) { BigDecimal newTotal = total.multiply(INTEREST_RATE); account.setTotal(newTotal); }
  • 24. Compiler Optimisations Lock Coarsening synchronized(account) { BigDecimal total = account.getTotal(); BigDecimal newTotal = total.multiply(INTEREST_RATE); account.setTotal(newTotal); }
  • 25. Compiler Optimisations Lock Elision public static void main(String... args) { ConcurrentMap<String,Integer> map; map = new ConcurrentHashMap<String, Integer>(); map.put("one", Integer.valueOf(1)); map.put("two", Integer.valueOf(2)); map.put("three", Integer.valueOf(3)); }
  • 26. Compiler Optimisations Lock Elision public class Foo implements Runnable { public void run() { synchronized(new Object()) { //Do something } } }
  • 27. What is a Memory Model A model to describe thread interaction with memory. Multiprocessors have different memory models. Inconsistently weak Enables to instruct memory fencing. Helps to write date race free Preserving program order.
  • 28. Java Memory Model A Memory Model for consistent thread behaviour with memory for all CPU architectures Alpha RISC PowerPC x86 AMD64 Pioneering Influential
  • 29. Java Memory Model History Initially broken volatile was not very volatile final was not very final Developers originally worked around locks. Huge open research area Constantly finding new ways to improve the JMM. People looking to go towards different ways of reasoning.
  • 30. Java Memory Model Goals 1. Allow as many compiler and hardware optimisations as possible. 2. Provide balance between optimisations and correctly synchronised code. 3. Provide developers to write and reason about multithreaded code.
  • 32. Java's synchronized keyword public class BankAccount { private BigDecimal total = new BigDecimal(0); public BigDecimal withdraw(BigDecimal amount) { total = total.minus(amount); return total; } public BigDecimal deposit(BigDecimal amount) { total = total.add(amount); return total; } public BigDecimal total() { return total; } }
  • 33. Symmetrical Multiprocessing deposit(200) withdraw(100) total() == 0 T1 T2 T3 BankAccount account = new BankAccount();
  • 34. Java's synchronized keyword public class BankAccount { private BigDecimal total = new BigDecimal(0); public synchronized BigDecimal withdraw(BigDecimal amount) { total = total.minus(amount); return total; } public synchronized BigDecimal deposit(BigDecimal amount) { total = total.add(amount); return total; } public synchronized BigDecimal total() {return total;} }
  • 35. Symmetrical Multiprocessing deposit(200) withdraw(100) total() == 100 T1 T2 T3 BankAccount account = new BankAccount();
  • 36. Java's volatile keyword @Singleton class FooFactory { private Foo foo; public Foo getFoo() { if (foo == null) { synchronized(this) { if (foo == null) { foo = new Foo("bar"); } } } return foo;
  • 37. Java's volatile keyword class Foo { private String name; public Foo(String name) { setName(name); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
  • 38. Symmetrical Multiprocessing new Foo() name == null name == "bar" foo = "bar"
  • 39. Java's volatile keyword @Singleton class FooFactory { private volatile Foo foo; public Foo getFoo() { if (foo == null) { synchronized(this) { if (foo == null) { foo = new Foo(); } } } return foo;
  • 40. Symmetrical Multiprocessing new Foo("bar") name == "bar" name == "bar" name == "bar"
  • 41. Java's volatile keyword @ThreadSafe class FooFactory { private static class FooHelper { public static Foo foo = new Foo(); } public static Foo getFoo() { return FooHelper.foo; } }
  • 42. Java's final keyword class MeaningOfLife { private final int answer; public MeaningOfLife(int answer){ this.answer = answer; } public int answer() { return this.answer; } }
  • 43. Final int answer = 42 int answer = 42 int answer = 42 MeaningOfLife life = new MeaningOfLife(42);
  • 44. Summary Memory ordering can change the program order of multithreaded code. Memory barriers inhibits optimisations for correct synchronisation. Java Concurrency Constructs: ensures mutual exclusion and memory visibility Happens-Before ordering: any subsequent lock acquisitions will see changes made by previous lock releases.