概述

用Java来开发多线程程序变得越来越常见,虽然Java提供了并发包来简化多线程程序的编写,但是我们有必要深入研究一下,才能更好的掌握这块知识。

本文主要对Java提供的底层原语synchronized和volatile进行分析,看看他们究竟干了什么,以及怎么样才能合理的使用它们。

运算速度与IO速度的问题

现代计算机模型,待计算的数据主要存储在内存中,CPU想要对数据进行计算,就必须要经过下面的流程:从内存读取数据-->CPU计算-->把计算结果写回内存。但是,不得不承认一个事实,就是CPU与内存之间的IO速度,要比CPU的运算速度慢很多,所以这样就不能充分发挥CPU的计算能力。

为了解决这个问题,引入了高速缓存的概念,它一般位于内存与CPU之间,与CPU之间有较高的IO速度。高速缓存存放常用的数据,这样就可以大幅度提高CPU的利用率。

由缓存命中问题引出的指令重排序

上面提到了高速缓存之间的概念。既然提到高速缓存,那么就要谈到缓存命中的问题,如果缓存命中率很高,那么整体性能就会提升。所以,试想一下,有下面几行代码:

int a = 0;
a = a + 10;
int b = 0;
b = b + 5;
a = a * 2;

通常我们会认为,执行完第2条代码后,a被写入到高速缓存,然后执行对b的操作,最后再从高速缓存中读取出a,再对a做乘法计算。

但是,现代编译器都会对这种情况做优化。考虑一个问题,既然两次对a操作的指令之间,没有使用到a的指令,那么为什么不在对a做完加法后,直接再对a做个乘法呢。反正又不会影响整个代码的语义,而且还能避免高速缓存不命中的问题,万一这之间执行的代码很多,然后a被清理出了高速缓存,那么到最后执行对a的乘法时,又要从内存中读取,这样看来,很不划算,所以就出现了指令重排。就是说指令真正的执行顺序,不一定是按照代码书写的顺序执行的,可能会打乱顺序执行,但是只要不影响整段代码的语义就行了,因为它们是“好像是串行执行”的方式。

比如下面的代码,如果对a的操作真的发生在对b的操作之前,那么就改变了整段代码的语义,所以这时候就不会重排指令。

int a = 0;
a = a + 10;
int b = 0;
b = b + a;
a = a * 2;

Java的存储(内存)结构

内存中,主要分为两大块区域:

1、全局区域,所有线程共享该区域。

2、线程私有区域,存放需要使用的全局数据的副本。

存储结构:

第一层,位于CPU内部的高速缓存,为了解决CPU与内存之间IO速度和CPU执行速度之间差距太大的问题。

第二层:内存(包括全局区域和线程私有区域)。

对一个变量的操作,通常需要经过下面的这8个步骤(如果不是同步操作,没有1和8)。见下图的蓝色字。

多线程要考虑的问题

1、内存一致性

某个变量,它在主内存中的值,应该和在线程工作内存中的值是一致的。

2、内存可见性

某个变量,如果一个线程对它进行修改,那么其他线程应该能立即看到它的变化。

3、有序性

如果一个线程A依赖另一个线程B的执行结果,那么在线程B看来是串行执行的指令(其实可能经过了指令重排),在线程A看来,就是一个错误的执行顺序。比如下面的情况:

Thread 1 Thread 2
x = 1; int r1 = y;
y = 2; int r2 = x;

有可能出现 r1 = 2 、r2 = 0 的情况,因为Thread1可能会进行指令重排,所以对于Thread2来说,就发生了错误。

synchronized工作原理

synchronized关键字,通过第1步,对主内存中变量加锁的操作(lock),获得了该变量的使用权,随后,其他线程没有访问这个被加锁变量的权利,一直到该线程使用完成,然后解锁该变量(unlock),之后其他线程才能访问该变量,当然也能看到该变量最新的结果。

由于synchronized以一种让上述8个步骤原子执行的方式工作,所以,它解决了内存一致性的问题,内存可见性的问题、有序性的问题。

使用场景:所有在有多线程共享数据的地方,都可以使用,简单粗暴,但是会引降低性能。

volatile工作原理

volatile关键字,通俗点来说,就是对一个变量的操作,2(read) 、3(load)、 4(use)这3个操作必须是原子的,而
5(assign)、6(store)、7(write)这3个操作也必须是原子的。

那么我们来看看,它能解决什么问题,因为简单来说就是,读(2 3 4)和写(5 6
7)操作分别都是原子的,相当于CPU每次都是直接和内存交互,所以高速缓存就变得无效了。而高速缓存变得无效,那么基本上,也就没有指令重排了。而由于每次改动都会直接写到内存,每次使用都从内存读取新的数据,所以也就满足了内存可见性。但是由于在读和写之间,其他线程也可以进行读和写,那么还是会出现内存一致性问题的。所以它解决了内存可见性、有序性、但是不能解决内存可见性。

        使用场景:由于volatile的特性,主要可以使用在下面的场景

1、不依赖于变量之前的状态的,比如一个 volatile boolean 来在一个线程中控制另一个线程的运行。

2、禁止指令重排,比如一个线程依赖于另一个线程真正的顺序执行结果,而不是语义上的顺序执行(其实是经过指令重排的)。

Java多线程之synchronized和volatile的更多相关文章

  1. JAVA多线程之synchronized和volatile实例讲解

    在多线程中,提到线程安全.线程同步,我们经常会想到两个关键字:volatile和synchronized,那么这两者有什么区别呢? 1. volatile修饰的变量具有可见性 volatile是变量修 ...

  2. (二)java多线程之synchronized

    本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/kco198 ...

  3. JAVA多线程之Synchronized关键字--对象锁的特点

    一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章 二,分析 s ...

  4. JAVA多线程之Synchronized、wait、notify实例讲解

    一.Synchronized synchronized中文解释是同步,那么什么是同步呢,解释就是程序中用于控制不同线程间操作发生相对顺序的机制,通俗来讲就是2点,第一要有多线程,第二当多个线程同时竞争 ...

  5. Java多线程之synchronized及其优化

    Synchronized和同步阻塞synchronized是jvm提供的同步和锁机制,与之对应的是jdk层面的J.U.C提供的基于AbstractQueuedSynchronizer的并发组件.syn ...

  6. Java多线程之synchronized详解

    目录 synchronized简介 同步的原理 对象头与锁的实现 锁的优化与升级 Monitor Record 锁的对比 synchronized简介 synchronized关键字,一般称之为&qu ...

  7. Java多线程之synchronized(四)

    前面几章都是在说synchronized用于对象锁,无论是修饰方法也好修饰代码块也好,然而关键字synchronized还可以应用到static静态方法上,如果这样写,那就是对当前的*.java文件所 ...

  8. Java多线程之synchronized(三)

    在多线程访问同一个对象中的不同的synchronized方法或synchronized代码块的前提下,也就是“对象监控器”为同一个对象的时候,也就是synchronized的锁为同一把锁的时候,调用的 ...

  9. java 多线程之synchronized wait/notify解决买票问题

    一.Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用线程对象的st ...

随机推荐

  1. ELF和BIN的区别,资料整理

    https://www.cnblogs.com/fah936861121/articles/8143556.html 1.Bin Bin文件是最纯粹的二进制机器代码, 或者说是"顺序格式&q ...

  2. java连接Oracle数据库,从ResultSet中提取数据出现java.sql.sqlException结果集已耗尽

    出现错误的原因是ResultSet中并没有任何东西,再调用next()方法就会出错,原因可能是oracle创建用户,表没有提交,commit即可

  3. C——简单计算器(HDU1237)

    题目: 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值.  Input测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔 ...

  4. 随着页面滚动,数字自动增大的jquery特效

    首先为了截出gif图,我下载了一个小工具 GifCam: https://www.appinn.com/gifcam/ 随着页面滚动,数字自动增大的jquery特效 主要就是依赖这个脚本script. ...

  5. SecureCRT的下载、安装( 过程非常详细!!值得查看)

    SecureCRT的下载.安装( 过程非常详细!!值得查看) 简单介绍下SecureCRT 一.SecureCRT的下载 二.SecureCRT的安装 简单介绍下SecureCRT SecureCRT ...

  6. Python——20200220Python123冲刺试卷 - 1

    知识点:面向对象继承,数组组织,文件操作,数据类型 1.面向对象的继承:继承是指类之间共享属性和操作的性质 2.软件危机的原因不包括:软件成本不断提高 软件危机原因: 软件开发生产率低.软件过程不规范 ...

  7. 深度(deepin)系统不能ssh root用户登录

    vi /etc/ssh/sshd_config找到这一部分信息刚进去信息应该是这样 # Authentication: #LoginGraceTime 2m #PermitRootLogin proh ...

  8. Your idea evaluation has expired. Your session will be limited to 30 minutes

    今天打开idea,出现了上面的话,试了网上的很多办法,获取注册码的那个方法是最常见的,那个网站现在不提供注册码了. ----两种方法-----**1)把提示框的x点掉,会自动打开idea**按最开始安 ...

  9. OHEM论文笔记

    目录 引言 Fast R-CNN设计思路 一.动机 二.现有方案hard negative mining 及其窘境 hard negative mining实现 窘境 设计思路 OHEM步骤: 反向传 ...

  10. Gird(2)

    目录 grid 布局(2) grid区域属性 网格线名称 grid-template-areas 属性 grid-auto-flow 容器内子元素的属性 grid 布局(2) grid区域属性 网格线 ...