java static 可见性_Java多线程 synchronized与可见性的关系以及可见性问题总结

c93d6615ba48ba5d8a75104c1446b528.png

作者:七里香的编程之路

出自:OSCHINA

原文:my.oschina.net/u/4098550/blog/4548274


能保证可见性的措施

除了volatile 可以让变量保证可见性外.happens-before九大规则. 都是能够保证可见性的. 其中就包含了锁操作(synchronized 和 lock) 和 volatile 修饰的变量

synchronized作用的升华

  • synchronized 关键字不仅仅保证了其代码块中的原子性 ,也保证了可见性. 例如如下代码中的i++操作 , 使用了synchronized 代码块保护起来, 使得两个线程对其相加的时候, 可以正确的得出20万的结果.
    这个结果不仅仅是保证了其i相加时候的原子性. 也说明保证了其可见性. 否则一个线程加完了之后, 另外一个线程没有获取i的最新的值的话, 也会导致相加的结果变少.

c143d578b6b30321a86596d4ed656fb2.png
  • synchronized 不仅仅让被保护的代码安全, 还会保证对synchronized 修饰的代码执行完毕之后, 下一个synchronized 进入之前, 整个synchronized 保护的代码块,都会被之后执行的代码看得到. 并且synchronized 之前的所有的代码也会被看到 . 如下面这幅图, 线程B拿到锁之后, 对于线程A的所有的操作都是可见的. 这是一个连带效应.

1aae121d3a180a6376eff008144c19ac.png

性的代码进行了修改. 把赋值操作的方法中, 最后一个变量的赋值, 加上了synchronized修饰. 打印的方法中, 第一行代码加上了synchronized修饰. 这样就保证了原子性和可见性. 写线程在执行完成d=6的时候, 会释放锁. 打印的线程获得锁的时候, 就能知道写线程的所有的操作, 获得其最新的值.

5f05939ab94ea9ca55b3c32dfdce9fd9.png
package com.thread.jmm;

/**
 * 类名称:FieldVisibility
 * 类描述:  演示可见性问题
 *
 * @author: https://javaweixin6.blog.csdn.net/
 * 创建时间:2020/9/5 14:31
 * Version 1.0
 */
public class FieldVisibility {

     int a = 1;
     int b = 2;
     int c = 3;
     int d = 4;

    //给a 赋值, 并把值给b
    private void change() {
        a = 3;
        b = a;
        c = a;
        synchronized (this) {
            d = 6;
        }
    }

    /**
     * 打印出a b
     */
    private  void print() {
        synchronized (this) {
            int aa = a ;
        }

        int bb = b ;
        int cc = c ;
        int dd = d ;

        System.out.println("b=" + b + ";a=" + a);
    }

    public static void main(String[] args) {

        while (true) {

            FieldVisibility test = new FieldVisibility();

            new Thread(() -> {

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

                //给 a b 重新赋值
                test.change();

            }).start();

            new Thread(() -> {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //给 a b 打印出来
                test.print();
            }).start();

        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值