这篇的主题本应该放在最初的几篇。讨论的是并发编程最基础的几个核心概念。可是这几个概念又牵扯到非常多的实际技术。比方Java内存模型。各种锁的实现,volatile的实现。原子变量等等,每个都可以展开写非常多,尤其是Java内存模型,网上已经可以有非常几篇不错的文章,临时不想反复造轮子。这里推荐几篇Jave内存模型的资料:

1. JSR-133 FAQ

2. JSR-133 Cookbook

3. Synchronization and Java Memory Model

4. 深入理解Java内存模型

我之前也写了一个Java内存模型的PPT: http://share.csdn.net/slides/7916

以下说说并发编程关注的几个核心概念。

关注一个并发问题,有3个主要的关注点:

1. 安全性。也就是正确性。指的是程序在并发情况下运行的结果和预期一致

2. 活跃性,比方死锁。活锁

3. 性能,降低上下文切换。降低内核调用。降低一致性流量等等

安全性问题是首要解决的问题。保证程序的线程安全。实际上就是对多线程的同步,而多线程的同步本质上就是多线程通信的问题。操作系统里面定义了几种进程通信的方式:

1. 管道 pipeline

2. 信号 signal

3. 消息队列 messsage queue

4. 共享内存 shared memory

5. 信号量 semaphore

6. Socket

Java里面进行多线程通信的主要方式就是共享内存的方式,共享内存基本的关注点有两个:可见性和有序性。加上复合操作的原子性。我们能够觉得Java的线程安全性问题主要关注点有3个

1. 可见性

2. 有序性

3. 原子性

Java内存模型JMM攻克了可见性和有序性的问题,而锁攻克了原子性的问题。

至于Java内存模型怎样解决可见性和有序性的问题,以后会说到,感兴趣的同学能够看看上面的资料。

可见性指的是一个线程对变量的写操作对其它线程兴许的读操作可见。因为现代CPU都有多级缓存,CPU的操作都是基于快速缓存的,而线程通信是基于内存的,这中间有一个Gap, 可见性的关键还是在对变量的写操作之后可以在某个时间点显示地写回到主内存,这样其它线程就能从主内存中看到最新的写的值。volatile,synchronized, 显式锁,原子变量这些同步手段都可以保证可见性。

可见性底层的实现是通过加内存屏障实现的:

1. 写变量后加写屏障。保证CPU写缓冲区的值强制刷新回主内存

2. 读变量之前加读屏障。使缓存失效,从而强制从主内存读取变量最新值

写volatile变量 = 进入锁

读volatile变量 = 释放锁

有序性指的是数据不相关的变量在并发的情况下。实际运行的结果和单线程的运行结果是一样的。不会由于重排序的问题导致结果不可预知。volatile, final, synchronized。显式锁都能够保证有序性。

有序性的语意有几层,

1. 最常见的就是保证多线程运行的串行顺序

2. 防止重排序引起的问题

3. 程序运行的先后顺序。比方JMM定义的一些Happens-before规则

 



重排序的问题是一个单独的主题。常见的重排序有3个层面:

1. 编译级别的重排序,比方编译器的优化

2. 指令级重排序,比方CPU指令运行的重排序

3. 内存系统的重排序,比方缓存和读写缓冲区导致的重排序





原子性是指某个(些)操作在语意上是原子的。比方读操作。写操作,CAS(compare and set)操作在机器指令级别是原子的,又比方一些复合操作在语义上也是原子的,如先检查后操作if(xxx == null){}

有个专有名词竞态条件来描写叙述原子性的问题。

竞态条件(racing condition)是指某个操作因为不同的运行时序而出现不同的结果,比方先检查后操作。

volatile变量仅仅保证了可见性,不保证原子性, 比方a++这样的操作在编译后实际是多条语句。比方先读a的值,再加1操作。再写操作。运行了3个原子操作,假设并发情况下,另外一个线程非常有可能读到了中间状态,从而导致程序语意上的不对。

所以a++实际是一个复合操作。

加锁能够保证复合语句的原子性。sychronized能够保证多条语句在synchronized块中语意上是原子的。

显式锁保证临界区的原子性。

原子变量也封装了对变量的原子操作。非堵塞容器也提供了原子操作的接口,比方putIfAbsent。


理解可见性,有序性。原子性是理解并发编程的一个重要基础

聊聊高并发(十九)理解并发编程的几种"性" -- 可见性,有序性,原子性的更多相关文章

  1. python学习笔记(十九)面向对象编程,类

    一.面向对象编程 面向对象,是一种程序设计思想. 编程范式:编程范式就是你按照什么方式去编程,去实现一个功能.不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,两种最重要的编程范式分 ...

  2. 转:【Java并发编程】之十九:并发新特性—Executor框架与线程池(含代码)

      Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.coc ...

  3. JAVA学习第五十九课 — 网络编程概述

    网络模型 OSI(Open System Interconnection)开放系统互连:參考模型 TCP/IP 网络通讯要素 IP地址 port号 传输协议 网络參考模型 七层OSI模型的基本概念要了 ...

  4. 五十九、linux 编程—— I/O 多路复用 fcntl

    59.1 介绍 前面介绍的函数如,recv.send.read 和 write 等函数都是阻塞性函数,若资源没有准备好,则调用该函数的进程将进入阻塞状态.我们可以使用 I/O 多路复用来解决此问题(即 ...

  5. 【Java并发核心九】并发集合框架

    1.List接口:ArrayList 和 Vector ArrayList不是线程安全的,Vector是线程安全的,Vector有一个子类,可实现后进先出(LIFO)的对象堆栈(LinkedList ...

  6. 流畅的python第十九章元编程学习记录

    在 Python 中,数据的属性和处理数据的方法统称属性(attribute).其实,方法只是可调用的属性.除了这二者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法 ...

  7. Java内存模型JMM 高并发原子性可见性有序性简介 多线程中篇(十)

    JVM运行时内存结构回顾 在JVM相关的介绍中,有说到JAVA运行时的内存结构,简单回顾下 整体结构如下图所示,大致分为五大块 而对于方法区中的数据,是属于所有线程共享的数据结构 而对于虚拟机栈中数据 ...

  8. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...

  9. 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁

    上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...

随机推荐

  1. The Future Of ReactiveCocoa by Justin Spahr-Summers

    https://www.bilibili.com/video/av9783052?from=search&seid=14165903430339282774

  2. 了解Linux的基础知识和一般概念

    1.GNU和GPL    GNU计划(又称革奴计划),是由Richard Stallman(理查德·斯托曼)在1983年9月27日公开发起的自由软件集体协作计划.它的目标是创建一套完全自由的操作系统. ...

  3. 四 numpy操作数组输出图片

    一.读取一张图片,修改颜色通道后输出 # -*- coding=GBK -*- import cv2 as cv import numpy as np #numpy数组操作 def access_pi ...

  4. appium使用教程(一 环境搭建)-------------2.安装部署

    1)      安装appium     2)      SDK(不建议使用模拟器,占用内存很大,会造成机器卡顿.另外模拟器还存在兼容性问题:pc为x86架构,绝大多数的手机都是ARM架构,app的兼 ...

  5. 洛谷1034 NOIP2002 矩形覆盖

    问题描述 在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示.例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7). 这些点可以 ...

  6. python中的future,你见过可以使用未来版本模块的语言吗?

    import xxx from yy.xxx import xx from yy.xxx import xx as x python最常见的导包导模块语句 yy为包名,包就是文件夹,模块就是xxx.p ...

  7. Android设置背景图片平铺

    以LinearLayout为例,它提供的background属性将会将背景图片拉伸,相当难看.其实我们仅仅需做少量的改动就能够实现web编程中css背景图片的效果.来试试吧. 创建反复的背景图片 在d ...

  8. java无依赖读取Excel文件

    说到Java读取Excel文件,用得多的当然是POI或jxls,但今天在看一本书的时候.当中提到使用JdbcOdbcDriver这个驱动类在不依赖第三方库的情况下也能够完毕对Excel文件的读取操作, ...

  9. mahout处理路透社语料步骤,转换成须要的格式

    首先下载路透社语料(百度就能够下载): 然后上传Linux 并解压到指定文件夹.Tips:此处我放在可 /usr/hadoop/mahout/reutersTest/reuters tar -zxvf ...

  10. HDU4565 So Easy! 矩阵高速幂外加数学

    easy 个屁啊,一点都不easy,题目就是要求公式的值,但是要求公式在最后的取模前的值向上取整.再取模,无脑的先试了高速幂 double  fmod来做,结果发现是有问题的.这题要做肯定得凑整数,凑 ...