这篇的主题本应该放在最初的几篇。讨论的是并发编程最基础的几个核心概念。可是这几个概念又牵扯到非常多的实际技术。比方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. codeforces#281 A

    脑子有点秀逗 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm ...

  2. zzulioj--1778-- 和尚特烦恼4——有多少战斗力(gcd)

    1778: 和尚特烦恼4--有多少战斗力 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 259  Solved: 123 SubmitStatusWe ...

  3. python(1)处理图像

    一提到数字图像处理,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因此, ...

  4. How Javascript works (Javascript工作原理) (十五) 类和继承及 Babel 和 TypeScript 代码转换探秘

    个人总结:读完这篇文章需要15分钟,文章主要讲解了Babel和TypeScript的工作原理,(例如对es6 类的转换,是将原始es6代码转换为es5代码,这些代码中包含着类似于 _classCall ...

  5. 学习Go语言之模板方法模式

    模板方法模式结构图如下.原理是过程实现不一样,但是执行的顺序是按照模板固定好了的.即简单理解为都有1,2,3步骤,但是每一步的实现交由具体实现类不同实现. 1.过程式编程 // 模板方法模式 pack ...

  6. jquery validate验证规则重用

    当多个控件验证规则相同时,如何避免冗余代码并应用相同规则呢? [1st way. addMethod+addClassRules] 场景:维护学生档案时需要维护父母.监护人.紧急联系人的身份证号码,此 ...

  7. 昼猫笔记 JavaScript -- 异步执行 | 定时器真的定时执行?

      本篇主要内容:异步.定时器引发的思考 预计阅读时间:8分钟 了解 我们都知道在js中定时器有两种  setInterval()  . setTimeout()   setInterval() :按 ...

  8. 创建vue.js项目

    vue init webpack test cd test npm install 或者 cnpm install test npm run dev

  9. Unity C# 设计模式(一)单例模式

    动机(Motivation):    在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性.以及良好的效率 意图:    保证一个类仅有一个实例,并提供一 ...

  10. 【Henu ACM Round#20 D】 Devu and Partitioning of the Array

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 一开始所有的数字单独成一个集合. 然后用v[0]和v[1]记录集合的和为偶数和奇数的集合它们的根节点(并查集 然后先让v[0]的大小 ...