简体   繁体   中英

Multithreading - Why does the following program behave this weirdly?

The outline of the program:
We have two threads ( t1 and t2 ) that write an integer value, then flush the written value to RAM.
Another thread ( t3 ) checks whether the value coincidences with the one written by t1 or t2 , and if not, prints it.

public class Container
{
     int a;
     volatile boolean b;


    public static void main(String[] args)
    {
        Container container = new Container();

        Thread t1 = new Thread()
        {
            @Override
            public void run()
            {
                for (;;)
                {
                    container.a = 409;
                    container.b ^= container.b;

                }
            }
        };

        Thread t2 = new Thread()
        {
            @Override
            public void run()
            {
                for (;;)
                {
                    container.a = 102;
                    container.b ^= container.b;
                }
            }
        };

        Thread t3 = new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(100);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                for (;;)
                {
                    if (container.a != 409 && container.a != 102 )
                        System.out.println(container.a);
                }
            }
        };

        t1.start();
        t2.start();
        t3.start();
    }
}

What I thought would happen:
Since a isn't volatile , I thought t3 would cache a and just never print anything.

What actually happens:
For a second or so (no matter long you let t3 sleep), it prints in rapid succession either 102 or 409. Then, printing stops (forever).

What exactly happens here?

container.a not being volatile doesn't mean it's mandatorily cached by t3 . All it means is that there are no guarantees whether it will be or not.

The reason it is free to print any value is the time-of-check-to-time-of-use problem here:

if (container.a != 409 && container.a != 102 )
   System.out.println(container.a);

As for why this exact behaviour on the exact environment you tested it in, we can only guess. But my money would be on the theory that while the code is run as interpreted, it will go and read container.a every time, but once it's compiled to native code by Hotspot, the value is only loaded into a register once, and that's the end of it. You can verify this hypothesis by using the -XX:+PrintCompilation command line flag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM