Java volatile 示例及扩展

public class VolatileTest {

    private static boolean stop = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("start");
            long i = 0;
            System.out.println("i:" + i);
            while (!stop){
                i++;
            }

            System.out.println("stop;i:" + i);
        }, "volatileTestThread");
        thread.start();
        System.out.println("set stop start");
        stop = true;
        System.out.println("set stop end");
    }
}

结果: 

set stop start
set stop end
start
i:0
stop;i:0

 volatileTestThread还没有开始,main线程就执行到stop = true了,所以加上main线程休眠继续测试。

public class VolatileTest {

    private static boolean stop = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("start");
            long i = 0;
            System.out.println("i:" + i);
            while (!stop){
                i++;
            }

            System.out.println("stop;i:" + i);
        }, "volatileTestThread");
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("set stop start");
        stop = true;
        System.out.println("set stop end");
    }
}

结果:

start
i:0
set stop start
set stop end

如果stop没有volatile修饰,volatileTestThread不会终止。stop加上volatile修饰继续测试。

public class VolatileTest {

    private static volatile boolean stop = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("start");
            long i = 0;
            System.out.println("i:" + i);
            while (!stop){
                i++;
            }

            System.out.println("stop;i:" + i);
        }, "volatileTestThread");
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("set stop start");
        stop = true;
        System.out.println("set stop end");
    }
}

结果:

start
i:0
set stop start
set stop end
stop;i:-1320028603

 volatile保证了线程volatileTestThread对stop的可见性。

示例中while循环被终止了。i最终为负值,是因为i曾经加到Integer.MAX_VALUE,再加1就会成为最小值(-2147483648),然后继续加,还没加到0就stop为true退出循环了。请看示例:

        int ii = Integer.MAX_VALUE;
        // 2147483647
        System.out.println(ii); 
        ii++;
        // -2147483648
        System.out.println(ii);
        // true
        System.out.println(ii == Integer.MIN_VALUE);
        // -2147483647
        ii++;
        System.out.println(ii);

 扩展一下(即使不加volatile也能终止volatileTestThread的多种方式):

(1)启动参数(VM options)设置-Djava.compiler=NONE,关闭JIT编译器。

(2)循环体中有释放锁的操作,同步主内存。比如:

           while (!stop){
                i++;
                // println里面有同步代码块
                System.out.println(i);
            }

或:

            while (!stop){
                i++;
                // 同步代码块
                synchronized (VolatileTest.class){
                }
            }

(3)循环体中有IO操作:

            while (!stop) {
                i++;
                new File("test.txt");
            }

(4)循环体中线程sleep或者yield,CPU时间片切换:

            while (!stop) {
                i++;
                try {
                    Thread.sleep(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            while (!stop) {
                i++;
                Thread.yield();
            }

(5)循环体中的i被volatile修饰:

public class VolatileTest {

    private static boolean stop = false;
    
    private static volatile int i = 0;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("start");
            while (!stop) {
                i++;
            }

            System.out.println("stop;i:" + i);
        }, "volatileTestThread");
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("set stop start");
        stop = true;
        System.out.println("set stop end");
    }
}

猜你喜欢

转载自blog.csdn.net/haoranhaoshi/article/details/108548363