多线程并发场景,理解Java的可见性

上一篇文章,编哥说了一些避免线程不安全的手段,关注点是对状态访问的限制,比如通过 synchronized 关键字

本章节,更关注从根上保证安全,也就是从对象本身出发,我们要设计一个安全地共享出去的对象

需要有什么原则呢?如果你要安全地共享你的对象给其他人用,可以关注下面4点

  • 可见性
  • 发布和逸出的风险
  • 线程封闭
  • 不可变性 和 安全发布

我们先看看第一个

可见性

我们除了可以使用synchronized 来划定 临界区,从而保证 阻塞 执行以及原子性,但是我们还要理解它背后还包含的:可见性

一个 可见性 的例子

class NoVisibility {
  static boolean ready;
  static int number;
  static class ReaderThread extends Thread {
    public void run() {
      while (!ready) Thread.yield(); // tt1 有可能 读取的 ready 一直是 false
      System.out.println(number);
    }
  }
  public static void main(String[] args) {
    new ReaderThread().start();
    number = 42;
    ready = true; // tt1 那里或许看不到 这里 变为 true 了
  }
}
// 结果是 tt1 那里会一直循环
// 或者 令人惊奇 地打印0,而非42(这就是 重排序 的现象; reordering)

synchronized 除了之前我们说的可以保证原子性,其实现在我们知道它也可以保证可见性,只要你把要读写的数据放入 synchronized 块(临界区)即可

这意味着,我们对 number 和 ready 变量的读写,应该用 synchronized 块包裹,如下意思:

class SynchronizedVisibility {
  static Object lock;
  static boolean ready;
  static int number;
  static class ReaderThread extends Thread {
    public void run() {
      synchronized (lock) {
        while (!ready) Thread.yield(); // tt1 有可能 读取的 ready 一直是 false
        System.out.println(number);
      }
    }
  }
  public static void main(String[] args) {
    new ReaderThread().start();
    synchronized (lock) {
        number = 42;
        ready = true; // tt1 那里或许看不到 这里 变为 true 了
    }
  }
}

volatile 变量是另外一个有名的选择,它也可以保证可见性,也是被称作较弱的同步形式;

代码就是如下样子:

class VolatileVisibility {
  volatile static boolean ready;
  volatile static int number;
  //... 其他的和第一版NoVisibility一样 
}

需要注意的是:volatile 不能保证原子性,只能保证可见性,比如 volatile 变量 count++ ,这个复合操作还是可能被拆成几步,来进行执行,后加动作或许因此变得不那么立即可见

总结

如果我们对对象的各种属性的可见性进行了合适的设定,那么我们的这个对象,就是可以安全的发布的一个必要的步骤

下一篇,编哥将会说一说:发布对象时它逸出的风险

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值