[TOC]

事先声明,我只是java并发的新手,这篇文章也只是我阅读《java并发编程的艺术》一书(内容主要涉及前3章)的一些总结和感悟。希望大家能多多讨论,对于错误的地方还请指出。

0. 简介

    程序的世界是有层次分明的,每层都对外封装细节而提供一些方式或者说接口来提供功能,甚至是约束功能来换取正确性等等。那么接下来,就用分层的思想作为灵魂,各种内存模型作为骨架,来简单讨论Java并发的原理。

1. 处理器内存模型

    我们面对的第一个问题是,一个好的处理器要满足什么条件?就像考试的学生一样,当然是做得又快,对得又多。对于处理器来说一般要满足两个条件:
    1. 效率
    2. 正确性
    

1.1 效率

    对于效率来说,处理器提供了很多的机制来满足这一点,并行,指令流水线,指令重排,缓存机制等等。但这些方式必须加以限制来保证正确性,或者说效率和正确性在一定程度上是相互制约的,我们必须加以权衡,合理折中。
    

1.2 正确性

    那么怎么保证正确性呢?同样除了处理器的一些内部的机制,比如禁止某些指令重排,缓存一致性,总线锁,缓存锁定等等,同时还向其上层提供了好的方法,比如说内存屏障,CAS等等,这些方法、机制会让上层(通过合理的方式)更好的来保证程序的正确性,就像Java会提供volatile,synchronized等等方式来让程序员(通过合理的方式)调用保证程序的线程安全。
    让我们更加深入这个话题,一个程序怎么样才叫正确?要满足什么性质?简单来说,有三条性质:
    1. 原子性,就是要么全部做要么全不做,需要硬件的配合,比如CAS。
    2. 可见性,由于缓存的存在,要让一个处理器处理的结果对其他处理器可见,首先要把缓存写入内存。
    3. 顺序性,程序必须保持一定的顺序依次的产生结果。

    注意,处理器的很多机制可以保持其中多种性质,比如内存屏障就可以把缓存刷新进入内存,而其他处理器的缓存无效来保证可见性,和通过禁止指令重排来保证顺序性。比如总线锁,缓存锁定,缓存一致性就通过各种方式来保证顺序性和原子性。
    

2. java内存模型

    好了我们更上一层楼,我们刚刚说在下一层(处理器)提供了各种机制来保证效率和正确性,而这一层正是要使用这些机制来到达这一层,也就是JRE和编译器的正确性和效率。
    JMM(即java内存模型)同处理器模型一样,也有很多的机制,包括各种优化。对外也提供volatile,synchronized和臭名昭著的concurrent包。上层的程序员也要使用(合理的方式)这些Java语言和包来保证线程安全。以下简单叙述一些本层次与上一层次的依赖(注意,synchronized因为JMM的优化可以分为3种)

    1. final域 -> 内存屏障

    2. volatile -> 内存屏障(字节码层次)-> 内存屏障(处理器层次)

    3. synchronized -> 偏向锁 + 轻量级锁 + 互斥锁
    偏向锁 -> CAS
    轻量级锁 -> CAS
    互斥锁 -> moniter -> 原子级处理器指令

    4. concurrent包 -> volatile + CAS

    注意CAS实现concurrent包中的原子操作可能会有三大问题:
    1. ABA问题。(解决办法:在变量前增加版本号)
    2. 循环时间长开销大。(解决办法:pause指令)
    3. 只能保证一个共享变量的原子操作。(解决办法:用锁或着合并操作)

    JMM把各种控制程序顺序性的机制抽象成文字形式,就是happens-before。其目的就是向Java开发者屏蔽特定平台的底层细节,设计的程序只要遵守happens-before就可以保证正确性。

3. 程序员

    这是最上面的层次,简单来说就是来利用好下层提供的机制来更好的编程。我想这也是我们要学习java并发原理的原因。

java并发 - 自底向上的原理分析的更多相关文章

  1. Java并发/多线程-CAS原理分析

    目录 什么是CAS 并发安全问题 举一个典型的例子i++ 如何解决? 底层原理 CAS需要注意的问题 使用限制 ABA 问题 概念 解决方案 高竞争下的开销问题 什么是CAS CAS 即 compar ...

  2. 原子类java.util.concurrent.atomic.*原理分析

    原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...

  3. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  4. Java NIO使用及原理分析 (四)

    在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...

  5. (6)Java数据结构-- 转:JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析  http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...

  6. Java并发-volatile的原理及用法

    Java并发-volatile的原理及用法 volatile属性:可见性.保证有序性.不保证原子性.一.volatile可见性 在Java的内存中所有的变量都存在主内存中,每个线程有单独CPU缓存内存 ...

  7. Java NIO使用及原理分析 (四)(转)

    在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...

  8. Java并发——volatile的原理

    111 Java并发——volatile的原理

  9. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

随机推荐

  1. python_如何为创建大量实例节省内存?

    案例: 某网络游戏中,定义了玩家类Player(id, name, status,....),每有一个在线玩家,在服务器程序内有一个Player的实例,当在线人数很多时,将产生大量实例(百万级别) 需 ...

  2. WebSphere--安全性

    WebSphere应用服务器具有很好的安全性支持.安全性简单地说就是确定谁可访问重要的系统资源,这些系统资源包括文件.目录.程序.连接和数据库.以独立模式运行WebSphere应用服务器比作为 Web ...

  3. 定时任务schedule(spring boot )

    1. 定时任务实现方式:SpringBoot自带的Scheduled,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多,本文主要介绍. 执行方式:单线程(串行)多线程(并行) ...

  4. Java数据结构和算法(十四)——堆

    在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...

  5. js实现键盘按键检测

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD ...

  6. js中的语句

    java语句与js的语句一样.1.判断if else/switch <script type=text/javascript> function fun1(){ var num = 10; ...

  7. 什么是<!DOCTYPE html>

    什么是<!DOCTYPE html>? 在HTML文档初,往往会有这么一句话<!DOCTYPE html>,那么它的意义是什么呢?它是html5标准网页声明,全称为Docume ...

  8. gulp最简示例

    全局安装 $ npm gulp -g 作为项目的开发依赖安装 $ npm gulp --save-dev 脚本文件 在根目录创建gulpfile.js文件 const gulp = require(' ...

  9. 100、RESTful API

    本篇导航: RESTful RESTful API设计 基于django实现 基于Django Rest Framework框架实现 一.RESTful REST与技术无关,代表的是一种软件架构风格, ...

  10. React ref回调函数例子

    ref属性也可以是一个回调函数而不是一个名字.   这个函数将要在组件被挂载之后立即执行. 这个参照的组件将会作为该函数的参数,这个函数可以立即使用这个组件参数,当然也可以将其保存供以后使用. 当这个 ...