java多线程——线程之间的可见性

目录

一、简介

二、volatile

三、synchronized

四、不会从主内存拉取的操作

五、从主内存中拉取的操作


一、简介

       我们知道线程在工作的时候有自己的私有内存,工作内存。程序运行的时候从主内存拉取需要的变量到工作内存,处理完再返回主内存。这篇文章总结哪些代码会使线程去主内存拉取变量。

二、volatile

       volatile修饰的变量,不论什么语句都会从主内存拉取变量。

public class Test01 {

    public volatile boolean b = true;

    public void m() {
        System.out.println("start");
        while(this.b){

        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

该程序能顺利完成,不会死循环。

三、synchronized

调用其他synchronized加锁的代码块,系统会从主内存拉取变量

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            synchronized(lock) {

            }
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

这种情况同样不会死循环。

注意,synchronized加锁后用到的变量才会从主内存拉取。

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        synchronized(lock) {
            while(this.b){

            }
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

这种情况,程序会死循环。 

四、不会从主内存拉取的操作

只要不影响到变量的值,变量不参与运算,则不会从主内存中拉取,比如while,if,赋值给其他变量,作为方法参数等

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            doSomething();
            if(b) {

            }
            boolean value = b;
        }
        System.out.println("end");
    }

    public void doSomething() {

    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

这种情况,程序会死循环。

如果调用了被synchronized加锁的方法,或者方法中有被synchronized加锁的代码块,那么变量将会从主内存中拉取。

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            doSomething();
        }
        System.out.println("end");
    }

    public void doSomething() {
        synchronized(lock) {

        }
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

调用的synchronized加锁的方法即使锁的是毫不相干的对象,同样会使得变量从主内存拉取

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            System.out.println(this.b);
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

这里的System.out.println锁的是PrintStream的实例,更是毫不相关

这种情况,程序不会死循环。 

五、从主内存中拉取的操作

变量被赋值,变量参与计算,比如加减乘除,字符串拼接,++,--等操作,线程休眠会使从主内存中拉取变量。

public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}
public class Test01 {

    public boolean b = true;

    public Object lock = new Object();

    public void m() {
        System.out.println("start");
        while(this.b){
            String str = b + "";
        }
        System.out.println("end");
    }

    public static void main(String[] args) {
        Test01 test = new Test01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.m();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("set");
        test.b = false;
    }

}

这种情况,程序不会死循环

猜你喜欢

转载自blog.csdn.net/guduyishuai/article/details/82777664