1
public class Main {
    static int i = 0;

    public static void main(String[] args) {
        for (; i < 2; i++)
            new Thread(() -> System.out.println(i)).start();
    }
}

I expected the code above to print out either

0
1

or

1
0

but to my surprise I got

2
2

Tom
  • 16,842
  • 17
  • 45
  • 54
sof
  • 9,113
  • 16
  • 57
  • 83
  • 1
    There is a dupe (not perfect, but [here is one](http://stackoverflow.com/a/26075774/3824919)) which explains that the lambda will be evaluated, when accessed (here by the thread itself) and `i` is already *"2"* (can also still be *"1"* in some cases) until the thread actually starts. That all depends on the scheduler. – Tom Jun 27 '16 at 00:32

3 Answers3

4

When you reference i in the body of class Main, what you are really doing is referencing the static variable Main.i (the compiler is polite and doesn't make you type the full path.) The lambda in this case isn't capturing anything; Main.i can be evaluated from a static context. So it is if the lambda is desugared to the method

public static void lambda$23() {
    System.out.println(Main.i);
}

What should be more clear now is that you've got multiple threads racing to access the shared (mutable!) variable Main.i; the main thread is updating it, and the created threads are reading it. And because the reads in the new thread are racy, you get no guarantees as to what is printed out.

Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
  • Hi Brian, very grateful for your explaining such little basic thing to me. I need read your book once again. – sof Jun 27 '16 at 01:24
2

I run the same program and it gives the same result for me too. But if you run it like that

for (; i < 2; i++) {
    Thread.sleep(10);
    new Thread(() -> System.out.println(i)).start();
}

results became

1
2

If you add Thread.sleep(10) below the new Thread(() -> System.out.println(i)).start(); it outputs

0
1

That's because of current thread(main) executes loop before the threads.

  1. Main Thread starts.
  2. Loop starts.
  3. Thread - 1 created.(Thread is still idle)
  4. Loop continuous.(i=1)
  5. Thread - 2 created.(Thread is idle)
  6. Loop ends.
  7. Main Thread ends.

Thread 1 and thread 2 starts between 2nd and 7nd step of your code. Operating system handles the thread scheduling so you can not expect the result in this program.

Tom
  • 16,842
  • 17
  • 45
  • 54
Abdullah Tellioglu
  • 1,434
  • 1
  • 10
  • 26
  • Ah I missed the second part where you moved the `Thread.sleep`. That's all ok :). – Tom Jun 27 '16 at 00:43
1

The results vary based on the scheduler. It cannot be predicted that it'll be 2,2 always. See the image below. You might end up getting different values also. This is because the OS has its own way of handling thread. You can read up more on threads here enter image description here------------------------------------------------------------------------------------------------------------------------------------ enter image description here The images show the eclipse output.

Tejus Prasad
  • 6,322
  • 7
  • 47
  • 75