深入理解Java虚拟机-内存模型及多线程

系列阅读
1.深入理解Java虚拟机-GC&运行时数据区
2.深入理解Java虚拟机-类文件结构及加载
3.深入理解Java虚拟机-内存模型及多线程

1. Java内存模型

主内存(Main Memory)是各个线程共享的内存区域,所有的变量都存储在主内存中。线程间变量值的传递需要通过主内存来完成。

工作内存(Working Memory)是每条线程都有属于自己的区域,工作内存保存了被该线程所使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)等都必须在工作内存中进行,而不能直接读写主内存中的变量。

勉强来说,主内存对应于物理硬件的内存,工作内存优先存储于寄存器和高速缓存中,因为程序运行时主要访问读写的是工作内存。

处理器、高速缓存、主内存间的交互关系

主内存与工作内存之间的交互协议,即读写同步的操作是原子的,不可再分的,包括以下8中操作:lock/unlock/read/write作用于主内存变量,use/assign/store/load作用于工作内存。

2. 线程同步

valatile同步
可以说是JVM中最轻量级的同步机制。
保证变量对所有线程的可见性,而普通变量不能保证这一点。
禁止指令重排序优化,保证变量赋值操作的顺序与程序代码的执行顺序一致。
优点:volatile变量读操作与普通变量几无差别,写操作时由于在本地代码中插入需要内存屏障质量来保证处理器不发生乱序执行,所以会慢一点。
volatile与锁之间选择的唯一依据是volatile能否满足使用场景的需求。

Java内存模型3大特性

  • 原子性
    可大致认为基本数据类型的访问读写是具备原子性的。synchronized块之间具备原子性。
  • 可见性
    指当一个线程改变了此值,新值对其他线程立即可见。Java内存模型通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的。volatile/普通变量/synchronized/final。
  • 有序性
    如果在本线程内观察,所有的操作都是有序的。如果在一个线程中观察另一个线程,所有的操作都是无序的。前半句是指“线程内表现为串行的语义”,后半句是指“指令重排序”现象和“工作内存与主内存同步延迟”的现象。valatile及synchronized可保证线程之间操作的有序性。synchronized规定了“一个变量在同一时刻只允许一条线程对其进行lock操作”。

线程的实现
线程的引入可以把一个进程的资源分配和执行调度分开,线程既可共享进程资源(内存地址、文件I/O等),也可独立调度(线程是CPU调度的基本单位)。
实现线程主要有3种方式:

  1. 使用内核线程实现
    轻量级进程(Light Weight Process, LWP)就是通常意义上的线程,每个LWP都由一个内核线程(Kernel-Level Thread,KTL)支持。


    轻量级进程与内核线程之间1:1的关系
  2. 使用用户线程实现
    广义上来说,一个线程只要不是内核线程,就可以认为是用户线程(User Thread,UT)。用户进程的建立、同步、销毁和调度完全在用户态中进行,不需要内核的帮助,所以,所有线程都需用户程序自己处理的话会异常困难。


    进程与用户线程之间1:N的关系
  3. 使用用户线程加轻量级进程混合实现
    这种混合实现下既存在用户线程也存在轻量级进程。用户线程完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价,并且可以支持大规模的用户线程并发。而操作系统提供支持的轻量级进程则作为用户线程和内核线程之间桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级进程来完成,大大降低了整个进程被完全阻塞的风险。


    用户线程与轻量级进程之间N:M的关系

线程调度
多线程系统的线程调度是指系统为线程分配处理器使用权的过程,主要调度方式为以下两种:
协同式调度:线程的执行时间由线程本身来控制;
抢占式调度:每个线程将有系统来分配执行时间。

线程的状态转换可参见Java并发编程学习笔记

3. 线程安全

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的操作,单次调用都可以获得正确的结果,那这个对象就是线程安全的。

线程安全的实现方法

  1. 互斥同步
    同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个(或者是一些,使用信号量的时候)线程使用。而互斥是实现同步的一种手段,临界区、互斥量、信号量都是主要的互斥实现方式。Java中可使用synchronized关键字和RetrantLock(重入锁)来实现同步,具体参见JAVA锁机制
  2. 非阻塞同步
    互斥同步主要问题是进行线程阻塞和唤醒所带来的性能问题,因此这种同步也叫阻塞同步。
    非阻塞同步是基于冲突检测的乐观并发策略,先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果有争用,产生了冲突,那就再采取其他的补偿措施。这种实现大都不需要把线程挂起。为了让操作和冲突检测这两个步骤具备原子性,需要硬件指令集的发展和支持。
  3. 无同步方案
    同步只是保证共享数据争用时的正确性的手段。如果一个方法不涉及共享数据则无需任何同步措施去保证正确性。比如可重入代码和县城本地存储。

操作共享的数据类型

  1. 不可变
    不可变(Immutable)对象一定是线程安全的。如果共享数据是基本数据类型,只要定义用final修饰则是不可变;如果是一个对象,需要保证对象的行为不会对其状态产生任何影响,比如String/Number部分子类/Long/Double/BigInteger/DigDecimal等。

  2. 绝对线程安全
    一个类不管运行时环境如何,调用者都不需要任何额外的同步措施。

  3. 相对线程安全
    需要保证对这个对象单独的操作是线程安全的,在调用的时候不需要做额外的保障措施。Java中大部分线程安全类都属于这种,例如Vector/HashTable/Collections的synchronizedCollection()方法包装的集合等。

  4. 线程兼容
    对象本身并不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中可以安全地使用。比如Vector/ArrayList/HashMap等。

  5. 线程对立
    无论调用端是否采取了同步措施,都无法在多线程环境中并发使用的代码。Java中很少出现。

注:主要内容摘录自书籍 深入理解Java虚拟机,周志明 著

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350