Coordinating Space and Time (Chicago Roboto 2017)

Coordinating Space and Time (Chicago Roboto 2017)

Video: https://www.youtube.com/watch?v=yS0Nc-L1Uuk
Code: https://github.com/swankjesse/concurrency

One of Android’s core requirements is that the UI runs on the main thread and IO in the background. Though concurrency is powerful, it’s also frustrating to deal with forking threads.

In this talk we’ll:

⏰ Learn how smartphone CPUs contradict your memory
⏰ Discuss how Android’s compilers disregard your orders
⏰ Sync up on Java’s concurrency APIs
⏰ See how to make sexy apps that aren’t racy
⏰ Determine if reactive programming is the future

This talk covers a sequence of concurrency topics. Attendees will be able to fix volatile programs and block threading bugs before they happen.

69252b3de5cb7f464c09301d9a6b0401?s=128

Jesse Wilson

April 20, 2017
Tweet

Transcript

  1. 2.

    Motivation • We want it all: • Fast, responsive apps

    • Simple, correct code • Exploring the underlying systems should help
  2. 5.

    Model vs. Machine • Code is abstract • Computers are

    concrete • Everything is particles bumping particles
  3. 9.
  4. 10.

    • Central Processing Unit • Where your code runs •

    For example, if your code wants to add a pair of integers, the CPU includes a mechanism that does that
  5. 11.

    • Random-Access Memory • Where your data is • When

    the CPU runs
 new ArrayList<String>()
 an area of memory is assigned to hold the corresponding object
  6. 12.

    CPU Registers • The CPU has 31 memory slots called

    registers • All input to the CPU must be loaded into a register • All output from the CPU is emitted to a register CPU register value 0 1 1 200 2 0 3 2147483647 4 32768 5 2 6 2147483646 7 300 8 9223372030 9 7483600 27 10 28 65535 29 1 30 0 . . .
  7. 13.

    offset value 0 200 8 0 16 2147483647 24 32768

    32 2 40 2147483646 48 300 56 9223372030 64 7483600 72 8675309 4,294,967,264 65535 4,294,967,272 1 4,294,967,280 9223372030 4,294,967,288 20 RAM • Just a contiguous range of 4 billion bytes • Read and write, and that’s it RAM . . .
  8. 15.

    public class PixelCounter {
 public static final int BLUE =

    100;
 public static final int RED = 200;
 
 int blueCount;
 int redCount;
 
 void count(int[] pixels) {
 for (int i = 0; i < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++; else if (pixel == RED) redCount++;
 }
 } }
  9. 16.

    public static void main(String[] args) {
 int[] pixels = new

    int[3]; pixels[0] = RED; // 200
 pixels[1] = RED; // 200
 pixels[2] = BLUE; // 100
 
 PixelCounter pixelCounter = new PixelCounter();
 pixelCounter.count(pixels);
 }a
  10. 17.

    public static void main(String[] args) {
 int[] pixels = new

    int[3]; pixels[0] = RED; // 200
 pixels[1] = RED; // 200
 pixels[2] = BLUE; // 100
 
 PixelCounter pixelCounter = new PixelCounter();
 pixelCounter.count(pixels);
 }a RAM offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  11. 18.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  12. 19.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  13. 20.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  14. 21.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  15. 22.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  16. 23.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 3 pixels.length
  17. 24.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  18. 25.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 <
  19. 26.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  20. 27.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  21. 28.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 200 pixel
  22. 29.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  23. 30.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  24. 31.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 ==
  25. 32.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  26. 33.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  27. 34.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 ==
  28. 35.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  29. 36.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  30. 37.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 0 redCount
  31. 38.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 0 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  32. 39.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0 ++
  33. 40.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 0
  34. 41.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 0
  35. 42.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  36. 43.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 0 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  37. 44.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 ++
  38. 45.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  39. 46.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  40. 47.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 3 3
  41. 48.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  42. 49.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 <
  43. 50.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  44. 51.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  45. 52.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 200 200
  46. 53.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  47. 54.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  48. 55.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 ==
  49. 56.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  50. 57.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  51. 58.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 ==
  52. 59.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  53. 60.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  54. 61.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 1 1
  55. 62.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 1 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  56. 63.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1 ++
  57. 64.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 1
  58. 65.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 1
  59. 66.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  60. 67.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 1 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  61. 68.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 ++
  62. 69.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  63. 70.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  64. 71.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 3 3
  65. 72.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  66. 73.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 <
  67. 74.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  68. 75.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 200 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  69. 76.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 100 200
  70. 77.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  71. 78.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  72. 79.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 ==
  73. 80.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  74. 81.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  75. 82.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 0 blueCount
  76. 83.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 0 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  77. 84.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2 ++
  78. 85.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 0 1064 redCount 2
  79. 86.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1064 redCount 2 1 0
  80. 87.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  81. 88.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 2 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  82. 89.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2 ++
  83. 90.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  84. 91.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  85. 92.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2 3 3
  86. 93.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  87. 94.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2 <
  88. 95.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++;
 else if (pixel == RED) redCount++;
 }x }y CPU RAM register name value 0 BLUE 100 1 RED 200 2 this 1048 3 pixels 1000 4 i 3 5 pixels.length 3 6 pixel 100 7 redCount 2 8 blueCount 1 offset name value 1000 type int[].class 1008 length 3 1016 0 200 1024 1 200 1032 2 100 1040 1048 type PixelCounter.class 1056 blueCount 1 1064 redCount 2
  89. 96.

    Inefficient Memory Access • Unnecessary: fetching values that we already

    have • Repetitive: fetching one value at a time • Lazy: not fetching until we need the value urgently • Redundant: writing values that we’ll re-write later
  90. 97.

    void count(int[] pixels) {
 for (int i = 0; i

    < pixels.length; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCount++; else if (pixel == RED) redCount++;
 }
 } void count(int[] pixels) { 
 int lengthR = pixels.length;
 int blueCountR = blueCount;
 int redCountR = redCount;
 for (int i = 0; i < lengthR; i++) {
 int pixel = pixels[i];
 if (pixel == BLUE) blueCountR++;
 else if (pixel == RED) redCountR++;
 }
 blueCount = blueCountR;
 redCount = redCountR;
 } Reordering Memory Accesses
  91. 102.

    Cheating on Memory Access • Only fetch each value once

    • Fetch adjacent values together • Anticipate reads and load eagerly • Defer writes
  92. 103.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  93. 104.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  94. 105.

    }a int[] newBlueRedMix(int size) {
 int[] result = new int[size];


    for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200; int blueCount(int[] pixels) {
 int result = 0;
 for (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b
  95. 106.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  96. 107.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200; int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c
  97. 108.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  98. 109.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200; boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e
  99. 110.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  100. 111.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200;
  101. 112.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200; Is this safe? • We guard access to the pixels with initialized • What if multiple threads call initializeAndCount?
  102. 113.

    }a int blueCount(int[] pixels) {
 int result = 0;
 for

    (int i = 0; i < pixels.length; i++) {
 if (pixels[i] == BLUE) result++;
 }g
 return result;
 }b int[] newBlueRedMix(int size) {
 int[] result = new int[size];
 for (int i = 0; i < result.length; ) {
 result[i++] = BLUE;
 result[i++] = RED;
 }d
 return result;
 }c boolean initialized;
 int[] pixels;
 
 int initializeAndCount(int size) {
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e public class PixelCounter {
 public static final int BLUE = 100;
 public static final int RED = 200; Unsafe! • One thread reorders the writes, writing initialized before pixels • Another thread reads the new value of initialized but the old value of pixels NullPointerException
  103. 116.

    // Invoked on the loader thread
 void processLoadedTasks(List<Task> tasks) {


    ... 
 for (Task task : tasks) {
 mCachedTasks.put(task.getId(), task);
 }
 ... }
 
 // Invoked on the Main thread
 void saveTask(Task task) {
 ...
 
 mCachedTasks.put(task.getId(), task);
 
 ... } • The Repository has a LinkedHashMap of todo items • The loader thread inserts task objects downloaded from the server • The UI inserts task objects entered by the user Is this safe?
  104. 117.

    • When multiple threads access the same object at the

    same time, bad things happen • The object could be corrupted, it could lose data, or it could crash Unsafe! // Invoked on the loader thread
 void processLoadedTasks(List<Task> tasks) {
 ... 
 for (Task task : tasks) {
 mCachedTasks.put(task.getId(), task);
 }
 ... }
 
 // Invoked on the Main thread
 void saveTask(Task task) {
 ...
 
 mCachedTasks.put(task.getId(), task);
 
 ... } ArrayIndexOutOfBoundsException
  105. 118.

    Fragile • Code that are correct in isolation may be

    broken when run concurrently • Tests don’t provide much confidence • One-in-a-million bugs happen all of the time
  106. 120.

    • Make a Runnable, create a Thread, and you’re done

    • Don’t forget to set a name! ExecutorService • Creating hundreds of threads is expensive • ExecutorService manages a list of threads, and accepts work to run on ’em • Don’t forget to set a name with ThreadFactory Thread VS
  107. 121.

    boolean initialized; int[] pixels;
 
 int initializeAndCount(int size) {
 if

    (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }f
 return blueCount(pixels);
 }e Volatile Fields volatile • Always read a fresh value from memory • Always write to memory immediately
  108. 122.

    • When you read a volatile field, all reads are

    refreshed • When you write a volatile field, all writes are flushed Volatile Isn’t Local
  109. 123.

    • blueCount++ does a read and a write • Another

    thread might write blueCount between the read and write Volatile Isn’t Atomic
  110. 124.

    int initializeAndCount(int size) { Synchronized Methods boolean initialized;
 int[] pixels;


    
 
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }
 return blueCount(pixels);
 } synchronized
  111. 125.

    • Every object has a lock • Calling a synchronized

    method: • Acquire the lock, waiting for other threads if necessary • Run the code • Release the lock How Synchronized Works
  112. 126.

    • When entering a synchronized block, all reads are refreshed

    • When exiting a synchronized block, all writes are flushed Synchronized & Memory
  113. 127.

    Synchronized is Blocking 0 1 2 3 4 5 6

    7 8 9 10 blueCount blueCount 0 blueCount 0
  114. 128.

    Synchronized is Blocking 0 1 2 3 4 5 6

    7 blueCount blueCount 13 blueCount 0
  115. 130.

    • Lock granularity: how many locks you have • Too

    many: correctness problems, risk of deadlock • Too few: jank, blocked threads • OkHttp has a 4-page design document describing its internal use of synchronized Synchronized is Difficult! https://github.com/square/okhttp/wiki/Concurrency
  116. 133.

    • Like HashMap, but for use by many threads •

    May be overkill for single-user applications ConcurrentHashMap
  117. 134.

    • Makes producer-consumer problems easy • Blocking put() for easy

    backpressure • Be careful about capacity BlockingQueue
  118. 135.

    ScheduledThreadPoolExecutor • Run code after a delay, or on a

    repeating interval • Handler.postDelayed() is often much better because you want to be on main thread
  119. 138.

    Main Thread is the Boss • It owns all data

    • It assigns immutable tasks to worker threads • Workers post immutable results back to the main thread
  120. 139.

    Immutable Values • Once an object is shared between threads,

    changing that object is unsafe • Objects that never change are always safe!
  121. 140.

    Implementing Immutable • All fields are final, and immutable •

    You’ll need builders • Be careful about collections • AutoValue • Kotlin data classes Effective Java JOSH BLOCH Version 2
  122. 141.

    Models go on the Main Thread • Mutable application state

    goes on the main thread • Keep your main thread synchronous • Avoid using Handler.post() from the main thread
  123. 142.
  124. 143.

    I/O goes on Worker Threads • Be deliberate about posting

    back to the main thread • Listeners • Libraries • @MainThread, @WorkerThread
  125. 144.

    final BehaviorSubject<List<Restaurant>> restaurantsSubject = BehaviorSubject.create();
 public void onUpdate(List<Restaurant> restaurants) {


    checkMainThread();
 restaurantsSubject.onNext(restaurants);
 }
 void checkMainThread() {
 if (Looper.myLooper() != Looper.getMainLooper()) {
 throw new AssertionError("Must be on main thread");
 }
 } Rx on Main
  126. 145.
  127. 146.

    Recap • Concurrency is difficult • There’s a bunch of

    language features and APIs • Access models on the main thread