3

I am new to Java8 and multithreading work. I tried this piece of code below

public class Test {
    public static boolean bchanged = true;

    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    if (bchanged != bchanged) {
                        System.out.println("here");
                    }
                }
            }
        }
        ).start();

        new Thread((Runnable) () -> {
            while (true) {
                bchanged = !bchanged;
            }
        }).start();
    }
}

when I was running this code, there is no print of "here". However, when I change

public static volatile boolean bchanged = true;

then the "here" will be printed out.

My original deduction was that, the lambda will have a local copy of the boolean value, and it won't affect the other thread when it is not volatile, but when I tried print out the boolean value in both threads, it proved I was wrong. So I am very confused in this case, how volatile affect the way lambda work.

MikaelF
  • 3,518
  • 4
  • 20
  • 33
LIP17
  • 69
  • 5
  • 4
    Lambdas have nothing to do with volatile fields. Please read this question: http://stackoverflow.com/questions/4885570/what-does-volatile-mean-in-java – ZhekaKozlov Feb 26 '17 at 06:21
  • When these other guys say your question is not about _lambdas_, they're trying to tell you that a lambda expression is just a shorthand way of defining an anonymous inner class and creating an instance of that class. There's nothing special about the class or the instance: They obey exactly the same rules as inner classes that are defined and instances that are created in the ordinary way. In your case, the inner class implements `Runnable`, but there's nothing magic about `Runnable` either. The magic that you're asking about happens because your code is executed by more than one thread. – Solomon Slow Feb 26 '17 at 17:15
  • 1
    The rules for capturing are exactly to avoid this kind of confusion: if you can modify the variable, the lambda expression (or inner class) can’t be implemented by having an unchanged copy of old value. Hence, fields can be changed and are not captured by value, whereas *local variables* are captured by value and must stay unchanged, read (effectively) `final`. – Holger Feb 27 '17 at 11:17

2 Answers2

7

This isn't about lambdas, this is about accessing a shared variable in multiple threads. You need to use synchronized, locks, AtomicBoolean, volatile, or some other thread-safety alternative. With the code you wrote the compiler is likely to cache the value of bchanged. It doesn't know that there's another thread modifying it, so the first thread sees a stale cached value.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Thanks for answering the question. And may I follow up a question here. If the "bchanged" is not volatile, is there any possibility that thread 1 clean the cache and read the modified value of "bchanged" again when it is evaluating the if-condition? – LIP17 Feb 27 '17 at 03:12
  • 1
    Yes, that's possible. The behavior is unpredictable. It might re-read the variable every time. It might never re-read it. It might re-read it sometimes but not others with no discernable pattern. You don't want to write code with unpredictable behavior. The most important point is that it's possible for it to *never* re-read the value. – John Kugelman Feb 27 '17 at 03:44
  • 1
    @LIP17: any construct that is specified to establish a “*happens-before*” relationship can act like a “clean the cache” action, if used correctly. This requires both threads to cooperate. If you declare `bchanged` as `volatile`, both threads see a `volatile` variables, hence, use the same mechanism. To be nitpicking, while it will do what you expect on most systems, it’s still not a formally correct program. Since the first thread contains an infinite loop without any wait states, there is no guaranty that the second thread ever runs. – Holger Feb 27 '17 at 11:26
0

As described in other answers, volatile and lambda has nothing to do together.
Volatile is printing "here" because the value of variable "bchanged" is not cached as "the volatile keyword in Java is used as an indicator to Java compiler and Thread that do not cache value of this variable and always read it from main memory".
You can use below links to understand more on volatile.
Read more: http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html#ixzz4ZlvIJYzZ
Cave of Programming: https://www.youtube.com/watch?v=_aNO6x8HXZ0&t=113s

Utsav
  • 5,572
  • 2
  • 29
  • 43