前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java多线程--对象的可见性

Java多线程--对象的可见性

作者头像
haoming1100
发布2018-10-10 10:09:17
7560
发布2018-10-10 10:09:17
举报
文章被收录于专栏:步履前行步履前行

  最近在看《Java并发编程实战》,并发方面的知识,今天看到了对象的可见性,在这里分享一下。

  在单线程环境中,如果向某个变量写入值(比如全局变量),在没有其他操作写入的情况下,总是能得到想要的值(因为在单线程环境中是线程安全的)。但是如果在多线程环境中,这个情况就会被打破。因为我们在执行某一线程的读操作的时候,其实并不知道是否有其他线程正在进行写操作,所以我们上面说到的可见性就在这里展开命题,我读操作的时候要知道另一个线程在写操作,这就是线程的安全性。其中书中提到了一点,

public class Main {
    private static boolean ready;
    private static int number;
    private static class ReaderThread extends Thread{
        @Override
        public void run() {
            while (!ready) {
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    public static void main(String[] args) {
        new ReaderThread().start();
        //new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

这段代码我跑了好多次,虽然输出的是42,但是其实应该符合书中之前说的偶然性,虽然结果是对的,但是我们的这段程序不一定是对的,也就是说最后的结果不一定永远都是42.这里就提到了一个概念,叫做重排序,就是Jvm为了充分的去利用现代CPU的多核处理的强大性能,对指令进行重新排序的一种操作,因此我们也叫它指令重排序。

  这里我们要注意重排序的概念,重排序并不单单是重新排序这个单一概念,而是分位编译时重排序和运行时重排序。我们来举例编译时重排序

  比如 int x = 1;

    int y = 2;

    x = x + 1;

  这里其实就进行了一次优化,y= 2 并不一定会在x+1前,(至于其中寄存器的读取,性能优化请各位自行查找)

  因此。我们了解到了重排序的概念,因此我们看到的结果其实和输出的结果是完全相反的,因为我们的想的是输出0,然后给number赋值42.

  在没有同步介入的情况下,我们完全无法得到我们想要的值。

  而且如果有一个读线程的操作的时候,我们给number赋值了42,但是它可能得到的仍然是0这个失效值,这里只是int类型的读取错误,如果我们在要求很严的环境中,读到一个失效的引用对象,这个对象的后续操作不可操作,造成的影响会特别大的。

public class Main {
    private int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

  大家看上面的这个代码,Main类不是线程安全的。因为set和get没有加同步,正如我们上面说到的一样,可能得到的结果和我们想要的差距很大,因此这里也不是线程安全的,如果想要线程安全,就要在方法上面加同步锁。

  上面说到了重排序,就不得不说Volatile 关键字了,加上这个关键字后,就表明修饰的变量是共享的,告诉编译器不要把这个变量与其他内存操作一起进行重排序,因此读取Volatile的变量时,读取到的值总会是写入的值。

  注意访问Volatile 并不会加锁,因此也就不会阻塞了,虽然性能上比Synchronized轻量级,但是牺牲了可见性,具体的不同我们在下一篇进行讲解。

  而且Volatile 并不足以保证比如 i++这类递增操作的安全性,而是常用来表示某个操作完成或者是结束的状态标识符。

  加锁机制可以确保可见性和原子性。而Volatile 只确保可见性。

  当满足下面情况才使用Volatile :

  • 对变量的操作不依赖当前的值。就是比如i++
  • 该变量不会是不可变类型。
  • 访问变量时不需要加锁
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档