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

    出现该错误,首先尝试以管理员身份运行 cmd.exe 程序,然后关闭所有的与 python 相关的进程. 1. open 打开一个文件夹(目录),而不是文件 这一错误一般发生在使用 open函数对文件 ...

  2. 4.Mocha的基本用法

    转自:http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html 有了测试脚本以后,就可以用Mocha运行它.请进 ...

  3. Google Codejam 2016 Round1A Problem C BFFs 简单图论

    链接 Google Codejam 2016 Round1A Problem C BFFs 题意 n个小朋友要坐成一个圈.每个小朋友心中都有一个Best Friend Forever.要保证每个人的左 ...

  4. 空值(NULL)和非空(NOT NULL)(十二)

    不多说,直接上干货! NULL:表示字段可以为空 NOT NULL:表示字段不允许为空 注意:NULL和NOT NULL不可以同时用于一个字段上. create table tb2( username ...

  5. CentOS7下安装二进制MYSQL8

    早看到MySQL8发布, 性能相比MySQL7提升2倍,今天准备安装下试试看 1.先卸载当前系统中已安装的mariadb rpm -qa | grep mariadb rpm -e mysql*/ma ...

  6. 【深入篇】自定义ExpandableListView,实现二级列表效果

    先看效果图: 上图是我们要实现的效果,那么现在我们开始着手去做,主要分为以下几步: 一丶我们需要根据效果图去思考该如何动手,从上图分析看,我们可以用一个相对布局RelativeLayout来完成gro ...

  7. C# HashSet<T> 简单使用

    一个简单的HashSet<T> 的例子,介绍其简单的方法,深入学习可参考微软:https://msdn.microsoft.com/en-us/library/bb359438(v=vs. ...

  8. 日常基础—————echo,print,print_r,var_dump的区别

    1.echo   函数输出一个或多个字符串. 代码: header("Content-Type:text/html; charset=utf-8"); echo "你好” ...

  9. GPU Command Buffer

    For Developers‎ > ‎Design Documents‎ > ‎ GPU Command Buffer This are mostly just notes on the ...

  10. 我的PHP学习之路

    由于工作中,做微信小程序需要我自己写一些后台代码.并且公司后台用的是php.所以我决定在周末和下班后抽空学习php.一开始,我想找一些入门视频来学,然后发现好像效率不是很好.不如看书来得痛快.(主要是 ...