Java基础-浅谈关键字volatile和synchronized

前言

这几天一直在学习Java并发相关的知识(比刚上大学那会儿看好多了,哈~),所以觉得有必要做一些知识总结。当我们在谈到并发或者查看一些开源库的源码的时候,我们会经常看到关键字volatilesynchronized,如果不了解这些关键字,其实还是挺头疼的。

目录

目录

一. 定义

volatilesynchronized是Java中的关键字

二. 作用

我们都知道,Java中某个线程在第一次读取共享属性之前,会从主内存中复制这个属性到线程的工作内存中,之后才会操作这个共享属性,在操作完成之后,如果共享属性的值发生了修改,则会先保存到本地的工作线程,然后才会刷新到主内存(貌似跟作用没什么关系,不过需要理解)。此外,在正式介绍这两个关键字作用之前,我觉得有必要了解三个名词:原子性、可视性和有序性

名词 解释
原子性 一个操作/一系列操作要么全部执行要么都不执行
可视性 如果一个线程对一个共享值作出了一些修改,其他线程都可以看到这个共享值的修改。
有序性 程序的运行顺序要和程序的逻辑顺序一致,可能实际情况是计算机考虑到性能的因素执行顺序有所不同,但是结果肯定会跟逻辑顺序一致。

下面来介绍我们今天的主角:
1. volatile
对于volatile的作用,《Java核心技术卷》是这么说的:

实例域的访问提供了一种免锁机制,不提供原子性

首先,实例域说明它是用来修饰域的,如下:

private volatile boolean isNum = false;

其次,对实例域的访问提供了免锁机制说明volatile具有可视性;最后的重点就是没有原子性。《Java编程思想》中提到:

所有的基础类型(除了doublelong)的基础操作(读取和写入)都具有原子性,经过volatile修饰的longdouble在基础操作中也会具有原子性。

所以volatile除了提供可视性之外,还能够为longdouble的读取和写入提供原子性,此外,volatile还可以保证有序性。
2. synchronized
在Java中,所有实例对象都自动含有单一的锁(也称监视器)。所以,当使用synchronized修饰的方法的时候,该方法会自动给实例加锁,这个时候,其他含synchronized的方法必须等到该方法调用结束并释放锁之后,该方法才能够被调用。简单来说,就是同一时间内,只能有一个线程访问 synchronized修饰的方法或者代码块啊,保证了原子性、有序性和可视性。

三. 使用

1. volatile
volatile的使用比较简单:

// 对一个域加上volatile,域可以确保可视性和有序性
private volatile int b;

// 对long和double加上volatile,可以使如下的读取和写入具有原子性。
private volatile long a;

public long getA(){ return a;}
public void setA(A a){ this.a = a;}

2. synchronized
相对于volatile的使用,synchronzied的使用相对复杂一点:

public class Test {
    private int a;
    public static int b;

    public synchronized void addOne() {
        a = a + 1;
    }

    public void addTwo() {
        synchronized (this) {
            a = a + 2;
        }
    }

    public void addThree() {
        synchronized (Test.class) {
            b = b + 3;
        }
    }

    public synchronized static void addFour() {
        b = b + 4;
    }
}

根据以上代码,我们看到synchronized的使用通常会分两种类型:

  • 对象锁,synchronized修饰普通方法或者在代码块中使用的当前对象,分别对应着addOne()addTwo()方法,该方法采用的是Test的对象锁,只针对单个Test实例的并发问题。
  • 类锁,synchronized修饰静态方法或者在代码块中使用类对象,分别对应这addFour()addThree(),这两个方法采用的是Test.Class的对象锁。当存在多个Test实例对象的时候,同一时间只有一个Test实例可以访问到addFour()方法或者addThree()中的代码块。

值得注意的是,一个任务可以多次获得对象的锁,当在一个synchronized方法中调用同一个对象的另一个synchronized方法,该方法就会使得JYM跟踪的线程的持有的锁的数量加一,方法调用结束的时候,持有锁的数量就会减一,直到数字减为零,锁才会被释放。

四. 进一步探究

在这里,我准备向各位同学浅析一下volatilesynchronized的作用。
1.volatile
从第二部分中,我们了解到volatile能够保证有序性和可视性以及为doublelong的读取和写入操作的原子性,除此之外,不会保证其他操作的原子性。

  • 有序性:(1)当执行包含volatile的域的读操作或者写操作的时候,在其前面的操作肯定已经全部进行,且结果对后面的操作可见,在其后面的操作肯定还没有进行。(2)Java在进行指令优化的时候,不能把volatile域的操作语句的前面的语句放在后面执行,也不能将其后面的语句放在前面执行。
  • 可视性:关于可视性我们直接引用《Java编程思想》的原文

只要对volatile域产生了写操作,那么所有的读操作都可以看到这个修改。即便使用了本地缓存,情况也确实如此,volatile域会被立即写入主存中,而读取操作就发生在主存中。

  • 非原子性:在Java中,只有对基本类型(除了longdouble,但是longdoublevolatile修饰后读取和写入会具有原子性)的变量的
    读取和写入才会确保有原子性,并且不包括自增这类跟之前值相关的操作,原因如下:
volatile int num = 1;
public void doAddOne() {
  num++;
  // 自增包括两个步骤:
  // 1. 读取num的值 2. num+1 写入修改后的值
  // 假设线程A在读取num值的时候,被挂起,这个时候线程B读取num的值
  // 线程B对num进行自增,结果为1
  // 这个时候,线程A恢复调度,对起初读取的num的值进行自增,结果也会1
  // 0经过两个自增,结果仍然为1,所以说volatile域并不能保证原子性
}

2. synchronized
这里,我们就简单的讨论一下synchronized的执行过程吧:
(1)获得同步锁。
(2)清空工作内存。
(3)从主内存中复制数据副本到工作内存。
(4)执行代码。
(5)刷新数据到主内存。
(6)释放锁。
这也就是synchronized能够具有可视性、有序性和原子性的原因。

五. 总结

总结

六. 拓展

其他解决并发的方式:

Java基础-浅析解决并发的几种方式

七. 引用

本人水平有限,难免会有错误,如有错误,欢迎各位同学指出~
如下是本人的参考:

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

推荐阅读更多精彩内容