Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Mutable State Monster and How to defeat it

Anup Cowkur
October 15, 2016

The Mutable State Monster and How to defeat it

Anup Cowkur

October 15, 2016
Tweet

Other Decks in Technology

Transcript

  1. WHAT IS STATE? WIKIPEDIA A computer program stores data in

    variables, which represent storage locations in the computer's memory. The contents of these memory locations, at any given point in the program's execution, is called the program's state.
  2. STATE IS THE CURRENT VALUE OF DATA AT ANY POINT

    OF EXECUTION OF THE PROGRAM –Me TEXT
  3. IT WAS ALSO ONE OF THE FIRST LANGUAGE TO HAVE

    ATOMS - DATA THAT COULD NOT BE DIVIDED FURTHER
  4. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
  5. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
  6. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
  7. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) { < - Thread 1
 map.put(key, value);
 }
 }
  8. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value);
 }
 } Thread 2 removes key from map
  9. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value); <- Thread 1
 }
 }
  10. public void checkAndPut(final String key,
 final String value) {
 if

    (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
  11. public void checkAndPut(final String key,
 final String value) {
 synchronized

    (this) {
 if (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
 }
  12. public void checkAndPut(final String key,
 final String value) {
 synchronized

    (this) {
 if (!map.containsKey(key)) {
 map.put(key, value);
 }
 }
 }
  13. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 return ++count;
 }
 }
  14. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 return ++count;
 }
 }
  15. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 return ++count;
 }
 }
  16. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 return ++count; <- Thread 1
 }
 }
  17. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read
 return ++count; 2. Modify
 3. Write 
 }
 }
  18. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read <- Thread 1
 return ++count; 2. Modify
 3. Write 
 }
 }
  19. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read <- Thread 1
 return ++count; 2. Modify
 3. Write 
 }
 } Thread 2 modifies the value of count
  20. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read
 return ++count; 2. Modify <- Thread 1
 3. Write 
 }
 }
  21. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read
 return ++count; 2. Modify
 3. Write <- Thread 1 
 }
 }
  22. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 1. Read
 return ++count; 2. Modify
 3. Write
 }
 }
  23. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 synchronized (this) {
 return ++count;
 }
 }
 }
  24. public class EntCounter {
 private long count = 0;
 


    public long increment() {
 synchronized (this) {
 return ++count;
 }
 }
 }
  25. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  26. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  27. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  28. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  29. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  30. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  31. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() { <- Thread 1
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  32. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() { <- Thread 2
 this.stopped = true;
 }
 }
  33. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) { <- Thread 1
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  34. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) { <- Thread 1
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 } MAIN MEMORY stopped
  35. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) { <- Thread 1
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 } MAIN MEMORY stopped THREAD LOCAL stopped
  36. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) { <- Thread 1
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 } MAIN MEMORY stopped THREAD LOCAL stopped L1/L2 PROCESSOR CACHE stopped
  37. public class RunFrodoRun {
 
 private boolean stopped = false;


    
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  38. public class RunFrodoRun {
 
 private volatile boolean stopped =

    false;
 
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  39. public class RunFrodoRun {
 
 private volatile boolean stopped =

    false;
 
 public void run() {
 while (!stopped) {
 // RUN!!!
 }
 }
 
 public void stop() {
 this.stopped = true;
 }
 }
  40. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  41. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  42. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  43. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  44. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  45. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  46. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1; <- thread 1
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  47. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() { <- Thread 2
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  48. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 } Result should be 1
  49. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 } But the JVM can re-order incorrectly synchronized operations
  50. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1; <- Operation 1
 orcsKilledToday = 2; <- Operation 2
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  51. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() { orcsKilledToday = 2; <- Operation 2
 orcsKilledYesterday = 1; <- Operation 1
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  52. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() { orcsKilledToday = 2; <- Thread 1
 orcsKilledYesterday = 1;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  53. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() { <- Thread 2
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  54. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() { orcsKilledToday = 2;
 orcsKilledYesterday = 1;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 } Result in this case will be 2
  55. public class OrcFunerals {
 int orcsKilledYesterday = 0;
 int orcsKilledToday

    = 0;
 
 public void init() { orcsKilledToday = 2;
 orcsKilledYesterday = 1;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  56. public class OrcFunerals {
 volatile int orcsKilledYesterday = 0;
 volatile

    int orcsKilledToday = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  57. public class OrcFunerals {
 volatile int orcsKilledYesterday = 0;
 volatile

    int orcsKilledToday = 0;
 
 public void init() {
 orcsKilledYesterday = 1;
 orcsKilledToday = 2;
 }
 
 public int getDeadOrcs() {
 return orcsKilledYesterday + orcsKilledToday;
 }
 }
  58. THE NUMBER OF TRANSISTORS IN A DENSE INTEGRATED CIRCUIT DOUBLES

    APPROXIMATELY EVERY TWO YEARS GORDON MOORE MOORE’S LAW
  59. CAN WE REPRESENT PROGRAMS AS A SERIES OF DATA TRANSFORMATIONS

    INSTEAD OF A SERIES OF SEQUENTIAL DATA MUTATIONS?
  60. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  61. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  62. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  63. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  64. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  65. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  66. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 }
  67. int[] numbers = {5,10,15};
 
 int sum() {
 int total

    = 0;
 
 for(int i=0; i<numbers.length ; i++) {
 total = total + numbers[i];
 }
 
 return total;
 } The result is 30
  68. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 }
  69. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 }
  70. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 }
  71. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 }
  72. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 }
  73. int compute() {
 return sum(sum(sum(0, 5), 10), 15);
 }
 


    int sum(int x, int y) {
 return x + y;
 } The result is still 30
  74. FUNCTIONAL PROGRAMMING IS ABOUT MODELLING OUR PROGRAMS IN TERMS OF

    EXPRESSIONS RATHER THAN STEP BY STEP INSTRUCTIONS
  75. THE IDEA IS TO BE AS DECLARATIVE AS POSSIBLE AND

    LET THE SYSTEM WORRY ABOUT LOW LEVEL DETAILS
  76. Book book = new Book(“Vol 2”, “Green”); book.setTitle(“Vol 3”); book.setColour(“Blue");

    The same book object can have different values at different points in time
  77. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  78. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  79. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  80. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  81. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  82. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks); <- Mutation
 }
 
 public List<String> getBooks() {
 return books;
 }
 }
  83. public class BookStore {
 private List<String> books;
 
 public BookStore(final

    List<String> books) {
 this.books = books;
 }
 
 public void addBooks(List<String> additionalBooks) {
 this.books.addAll(additionalBooks);
 }
 
 public List<String> getBooks() {
 return books;
 }
 } How do we make this immutable?
  84. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  85. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  86. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  87. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  88. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) { <- Deep copy
 copy.add(book);
 }
 return copy;
 }
 }
  89. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy; <- Return deep copy, not the original
 }
 }
  90. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  91. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks(); <- Get deep copy
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  92. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks); <- Add to deep copy 
 
 return new BookStore(newBooks);
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  93. public class BookStore {
 private final List<String> books;
 
 public

    BookStore(final List<String> books) {
 this.books = books;
 }
 
 public BookStore addBooks(List<String> additionalBooks) {
 List<String> newBooks = getBooks();
 
 newBooks.addAll(additionalBooks);
 
 return new BookStore(newBooks); <- Return a new BookStore
 }
 
 public List<String> getBooks() {
 List<String> copy = new ArrayList<>();
 for (String book : books) {
 copy.add(book);
 }
 return copy;
 }
 }
  94. BOOK STORE UI Thread BOOK STORE 1 Background Thread Meanwhile,

    Another background thread writes to our store
  95. BOOK STORE UI Thread BOOK STORE 1 Background Thread It

    gets it’s own copy do whatever it wants BOOK STORE FOR THREAD 2 Background Thread 2
  96. BOOK STORE UI Thread BOOK STORE 1 Background Thread No

    lock based synchronization necessary BOOK STORE FOR THREAD 2 Background Thread 2