并发和多线程-说说面试常考平时少用的volatile

说到volatile,一些参加过面试的同学对此肯定不陌生。

它是面试官口中的常客,但是平时的编码却很少打照面(起码,我是这样的)。

最近的面试,我也经常会问到volatile相关的问题,比如volatile和sychronized的区别volatile的使用场景volatile的实现原理等等。

问这些问题其实主要还是考察多线程、锁等方便的知识储备。虽然volatile在我们日常编码使用不多,但是他的实现思想以及背后牵扯的一些概念还是值得我们学习和思考的。

举例

首先我们来看一个例子


<pre style="margin: 0.5em 0px; padding: 0.4em 0.6em; border-radius: 8px; background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; font-family: Menlo; font-size: 9pt;">public class VolatileExample extends Thread {

    private static boolean flag = false;

    public void run() {
        while (!flag) {
        }
    }

    public static void main(String[] args) throws Exception {
        new VolatileExample().start();
        Thread.sleep(100);
        flag = true;
    }
}</pre>

这段代码并不长。

  • 声明了一个布尔类型的静态变量flag,初始值为false;

  • main函数中启动了一个线程VolatileExample,集成自Thread类;

  • 除去VolatileExample线程,当然还有一个主线程main;

  • 主线程sleep 100毫秒,并在其后置flag为true;

那么,你觉得运行main会怎样

  • 顺利跑完所有代码,结束?

  • 程序一直在等待,不会结束?

我们看下运行的结果

image

从结果可以发现,主线程运行结束后,界面中左边的红点并没有消失,表示程序还没有结束。

这是因为启动的VolatileExample线程读取到的flag一直都是false。

虽然主线程中flag已经被赋值为true,但是VolatileExample线程却视而不见,这是为什么呢,这就涉及到一个可见性的问题。

可见性

这里假设大家都是对线程以及锁等知识有一定的了解

sychronized我们应该都用过或者了解过,这是为了在多线程环境下对共享资源添加一个标识,用于锁住共享资源,防止多线程同时进入对数据操作产生不一致的现象。

我们平时说的加锁其实表面上是为了达到一种互斥的效果,也就是对于同时存在的线程A和线程B,如果这时候线程A或者锁,则线程B只能在旁边乖乖的等,这就是一种互斥,有你没我,有我没你!

但是加锁的本质是解决了可见性的问题。具体先不说这个问题,我们先结合上面的例子来说说可见性的问题。后面在结合可见性可能更好理解加锁的本质。

在java内存模型中,是分为主内存工作内存两块的。

主内存,主要是存储各个线程都会用到共享变量等。

对于每个线程都有自己的一个存储变量的地方,就是工作内存。各个线程之间的工作内存是相互独立的,不可见的。

到这里,你可能已经知道上面例子的程序为什么一直出于运行的状态没有终止了。没错,VolatileExample线程读取的flag值是自己线程中存储在工作内存中的值,主线程中的flag值虽然更新了,但是对于VolatileExample是不可见、无感知的。

所以,这时候volatile关键字就排上用场了。我们在flag变量钱添加volatile关键字修饰。再次运行程序

image

效果显而易见,主线程和VolatileExample线程一同结束。

这是因为使用volatile关键字修饰,该变量是强制要求从主内存读以及往主内存写,这样保证各个线程在操作这个变量的值时,都是最新鲜的数据。

这时候,我们再来回顾刚刚说到加锁的本质是解决可见性问题。

volatile是强制让所有线程都从一个地方操作共享资源,使得原来是从每个线程的副本中读取变量变为从主内存读取变量,从而解决了可见性问题。

而sychronized也是解决了可见性问题,它不允许同一时间有两个线程操作同一共享资源,因为其无法保证可见性。所以其通过独占互斥的方式,保证自己执行完之后才会有下一个执行,这样每次只有一个线程占有资源,也是间接的解决了可见性的问题。

说到这,就不得不提另外一个问题——原子性

原子性


private int num = 0;

num++;

上面的代码符合原子性么?

显然不符合,假如现在有线程A和线程B两个线程,

线程A读取num=0,准备执行num++的操作,

但是还没有执行“++”操作之前,线程B读取num的值,此时值为0,之后也执行num++的操作,

最后A和B两个线程最终得到的值都是1,

这是不符合原子性的。

通过如下的sychronized的修饰就符合原子性了


sychronized(this) {

    num++;

}

其道理还是因为sychronized的独占性。

那么volatile是否可以保证原子性呢

答案是否定的。道理和上面没有加sychronized的描述是一样的。

线程A还有执行完num++后,线程B也来访问num值,得到的是0,然后执行num++,最终还是两个线程得到的值都是1。

那么volatile有哪些使用场景呢。

volatile的适用场景

  • volatile是在synchronized性能低下的时候提出的。如今synchronized的效率已经大幅提升,所以volatile存在的意义不大。

  • 如今非volatile的共享变量,在访问不是超级频繁的情况下,已经和volatile修饰的变量有同样的效果了。

  • volatile不能保证原子性,这点是大家没太搞清楚的,所以很容易出错。

  • volatile可以禁止重排序(sychronized也是可以的)。

其实与之相关概念还有重排序、happens-before,as-if-serial等等,限于篇幅,不再详述。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容