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. @jessewilson https://github.com/swankjesse/concurrency Coordinating Space and Time

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

    • Simple, correct code • Exploring the underlying systems should help
  3. Plan • Why concurrency is difficult? • All the concurrency

    APIs • A recipe for success
  4. Why is Concurrency Difficult? PART 1

  5. Model vs. Machine • Code is abstract • Computers are

    concrete • Everything is particles bumping particles
  6. iFixit, https://www.ifixit.com/Teardown/Google+Pixel+XL+Teardown/71237

  7. iFixit, https://www.ifixit.com/Teardown/Google+Pixel+XL+Teardown/71237

  8. iFixit, https://www.ifixit.com/Teardown/Google+Pixel+XL+Teardown/71237

  9. None
  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
  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
  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 . . .
  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 . . .
  14. Example: Pixel Counter blueCount 1 redCount 2

  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++;
 }
 } }
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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 <
  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
  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
  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
  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
  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
  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 ==
  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
  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
  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 ==
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 <
  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
  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
  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
  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
  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
  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 ==
  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
  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
  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 ==
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 <
  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
  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
  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
  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
  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
  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 ==
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 ++
  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
  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
  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
  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
  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 <
  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
  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
  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
  98. CPU
 CORE 248 RAM 4,294,967,296

  99. CPU
 CORE 248 RAM 4,294,967,296 L1 65,536

  100. CPU
 CORE 248 RAM 4,294,967,296 L1 65,536 L2 1,572,865

  101. CPU
 CORE RAM L1 L2 CPU
 CORE L1 CPU
 CORE

    L1 CPU
 CORE L1
  102. Cheating on Memory Access • Only fetch each value once

    • Fetch adjacent values together • Anticipate reads and load eagerly • Defer writes
  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;
  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;
  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
  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;
  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
  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;
  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
  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;
  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;
  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?
  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
  114. Surprise! • Reordered code and memory access make impossible things

    possible
  115. https://github.com/googlesamples/android-architecture

  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?
  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
  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
  119. An Inventory of Weapons PART 2

  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
  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
  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
  123. • blueCount++ does a read and a write • Another

    thread might write blueCount between the read and write Volatile Isn’t Atomic
  124. int initializeAndCount(int size) { Synchronized Methods boolean initialized;
 int[] pixels;


    
 
 if (!initialized) {
 pixels = newBlueRedMix(size);
 initialized = true;
 }
 return blueCount(pixels);
 } synchronized
  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
  126. • When entering a synchronized block, all reads are refreshed

    • When exiting a synchronized block, all writes are flushed Synchronized & Memory
  127. Synchronized is Blocking 0 1 2 3 4 5 6

    7 8 9 10 blueCount blueCount 0 blueCount 0
  128. Synchronized is Blocking 0 1 2 3 4 5 6

    7 blueCount blueCount 13 blueCount 0
  129. Synchronized is Blocking 0 1 2 3 blueCount blueCount 13

    blueCount 13
  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
  131. • AtomicInteger, AtomicReference, etc. • Non-blocking like volatile, atomic like

    synchronized Atomics
  132. • 3, 2, 1, blast off! CountDownLatch

  133. • Like HashMap, but for use by many threads •

    May be overkill for single-user applications ConcurrentHashMap
  134. • Makes producer-consumer problems easy • Blocking put() for easy

    backpressure • Be careful about capacity BlockingQueue
  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
  136. CONCURRENCY IN PRACTICE JAVA BRIAN GOETZ AND FIVE OTHER GENIUSES

  137. Effective Concurrency PART 3

  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
  139. Immutable Values • Once an object is shared between threads,

    changing that object is unsafe • Objects that never change are always safe!
  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
  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
  142. None
  143. I/O goes on Worker Threads • Be deliberate about posting

    back to the main thread • Listeners • Libraries • @MainThread, @WorkerThread
  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
  145. None
  146. Recap • Concurrency is difficult • There’s a bunch of

    language features and APIs • Access models on the main thread
  147. @jessewilson https://github.com/swankjesse/concurrency Thanks