这篇的主题本应该放在最初的几篇。讨论的是并发编程最基础的几个核心概念。可是这几个概念又牵扯到非常多的实际技术。比方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. nyoj--42--一笔画问题(并查集)

    一笔画问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. ...

  2. django 笔记7 多对多

    多对多 方法一 :双外键关联 自定义关系表 自定义 class Host(models.Model): nid = models.AutoField(primary_key=True) hostnam ...

  3. jsp输出当前时间

    在jsp页面中输出完整的时间,格式为"年 月 日  时:分:秒" <% Date date = new Date(); SimpleDateFormat t = new Si ...

  4. vuejs keep-alive

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. watchpoint set variable

    watchpoint set variable string_weak_assign Watchpoint created: Watchpoint 3: addr = 0x10fcaa468 size ...

  6. windos下安装多个mysql服务

    最近需要使用Mysql制造大量数据,需要多个Mysql服务器.一开始的解决方案是使用多个windows机器.实体机不够,则用虚拟机来搞.但,,,,安装多个虚拟机…….好吧, 在网上查了下,有使用单个机 ...

  7. 学习Go语言之单例模式

    单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建.这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象 // 单例模式 package main ...

  8. [USACO07DEC]道路建设Building Roads

    题目:洛谷P2872.POJ3625. 题目大意:给你n个点的坐标,有些点已经有边连通,现在要你连上剩下的所有点,求这些边的最小长度是多少(不包括原来的边). 解题思路:最小生成树,把所有边处理出来, ...

  9. 解决zabbix容器中文无法选择的问题

    1.查看zabbiz-web运行的容器 2.进入容器 3.安装语言包(针对centos7) yum install -y kde-l10n-chinese 4.更新gitbc包(因为镜像阉割了该包的部 ...

  10. 【Henu ACM Round#19 A】 Vasya the Hipster

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟题. 两个一起用->min(a,b); 剩下的除2加上去就好 [代码] #include <bits/stdc++. ...