原文地址:http://www.jameswxx.com/java/%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E6%80%BB%E7%BB%93%EF%BC%88%E4%BA%8C%EF%BC%89/

站内很多人都问我,所谓线程的“工作内存”到底是个什么东西?有的人认为是线程的栈,其实这种理解是不正确的。看看JLS(java语言规范)对线程工作 内存的描述,线程的working memory只是cpu的寄存器和高速缓存的抽象描述。

可能 很多人都觉得莫名其妙,说JVM的内存模型,怎么会扯到cpu上去呢?在此,我认为很有必要阐述下,免 得很多人看得不明不白的。先抛开java虚拟机不谈,我们都知道,现在的计算机,cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级 是:寄存器-高速缓存-内存。线程耗费的是CPU,线程计算的时候,原始的数据来自内存,在计算过程中,有些数据可能被频繁读取,这些数据被存储在寄存器 和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存。当个多个线程同时读写某个内存数据时,就会产生多线程并发问题,涉及到三个特 性:原子性,有序性,可见性。在《线程安全总结》这篇文章中,为了理解方便,我把原子性和有序性统一叫做“多线程执行有序性”。支持多线程的平台都会面临 这种问题,运行在多线程平台上支持多线程的语言应该提供解决该问题的方案。

那么,我们看看JVM,JVM是一个虚拟 的计算机,它也会面临多线程并发问题,java程序运行在java虚拟机平台上,java程序员不可能直接去控制底层线程对寄存器高速缓存内存之间的同 步,那么java从语法层面,应该给开发人员提供一种解决方案,这个方案就是诸如synchronized, volatile,锁机制(如同步块,就绪队 列,阻塞队列)等等。这些方案只是语法层面的,但我们要从本质上去理解它,不能仅仅知道一个 synchronized 可以保证同步就完了。   在这里我说的是jvm的内存模型,是动态的,面向多线程并发的,沿袭JSL的“working memory”的说法,只是不想牵扯到太多底层细节,因为 《线程安全总结》这篇文章意在说明怎样从语法层面去理解java的线程同步,知道各个关键字的使用场 景。

今天有人问我,那java的线程不是有栈吗?难道栈不是工作内存吗?工作内存这四个字得放到具体的场景 中描述,方能体现它具体的意义,在描述JVM的线程同步时,工作内存指的是寄存器和告诉缓存的抽象描述,具体请自行参阅JLS。上面讲的都是动态的内存模 型,甚至已经超越了JVM的范围,那么JVM的内存静态存储是怎么划分的?今天还有人问我,jvm的内存模型不是有eden区吗?也不见你提起。我跟他 说,这是两个角度去看的,甚至是两个不同的范围,动态的线程同步的内存模型,涵盖了cpu,寄存器,高速缓存,内存;JVM的静态内存储模型只是一种对内 存的物理划分而已,它只局限在内存,而且只局限在JVM的内存。那些什么线程栈,eden区都仅仅在JVM内存。

说说JVM的线程栈和有个朋友反复跟我纠结的eden区吧。JVM的内存,被划分了很多的区域:

1.程序计数器
每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令。
2.线程栈
线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果VM栈可以动态扩展(VM Spec中允许固定长度的VM栈),当扩展时无法申请到足够内存则抛出OutOfMemoryError异常。
3.本地方法栈
4.堆

每个线程的栈都是该线程私有的,堆则是所有线程共享的。当我们new一个对象时,该对象就被分配到了堆中。但是堆,并不是一个简单的概念,堆区又划分了很多区域,为什么堆划分成这么多区域,这是为了JVM的内存垃圾收集,似乎越扯越远了,扯到垃圾收集了,现在的jvm的gc都是按代收集,堆区大致被分为三大块:新生代,旧生代,持久代(虚拟的);新生代又分为eden区,s0区,s1区。新建一个对象时,基本小的对象,生命周期短的对象都会放在新生代的eden区中,eden区满时,有一个小范围的gc(minor gc),整个新生代满时,会有一个大范围的gc(major gc),将新生代里的部分对象转到旧生代里。
5.方法区 
其实就是永久代(Permanent Generation),方法区中存放了每个Class的结构信息,包括常量池、字段描述、方法描述等等。VM Space描述中对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存,也可以选择固定大小或者可扩展外,甚至可以选择不实现垃圾收集。相对来说,垃圾收集行为在这个区域是相对比较少发生的,但并不是某些描述那样永久代不会发生GC(至 少对当前主流的商业JVM实现来说是如此),这里的GC主要是对常量池的回收和对类的卸载,虽然回收的“成绩”一般也比较差强人意,尤其是类卸载,条件相当苛刻。
6.常量池
 Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量表(constant_pool table),用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)。

关于垃圾收集,在此不多说,流到垃圾收集那一章再详细说吧。关于java的同步,其实还有基于CPU原语的比较并交换的非阻塞算法(CAS),不过这个在java的并发包里已经实现了很多,因此关于这点,就留到java并发包那一章介绍吧。后面我会专门写一篇文章,JVM内存与垃圾收集。

java线程安全总结 - 2 (转载)的更多相关文章

  1. JAVA线程安全总结(转载)

    JAVA线程安全总结(一) JAVA线程安全总结(二) 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣.已经拟好了提纲,大概分为这几个主题: java线程安全,jav ...

  2. 50道Java线程面试题(转载)

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成 ...

  3. 从Tomcat无法正常关闭讲讲Java线程关闭问题【转载】

    正常情况下,会优先采用catalina.sh stop来停止Tomcat实例,这样可以让服务有机会处理完请求,并做好善后工作. 但如果通过catalina.sh stop命令无法关闭Tomcat实例, ...

  4. java线程中断[interrupt()函数] (转载)

    一个正常的线程中断: 从运行到真正的结束,应该有三个阶段: 正常运行. 处理结束前的工作,也就是准备结束. 结束退出. Java曾经提供过抢占式限制中断,但问题多多,例如的Thread.stop.另一 ...

  5. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

  6. (转载)JAVA线程池管理

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...

  7. Java线程面试题 Top 50 (转载)

    转载自:http://www.cnblogs.com/dolphin0520/p/3958019.html 原文链接:http://www.importnew.com/12773.html   本文由 ...

  8. 【多线程】Java线程面试题 Top 50(转载)

    Java线程面试题 Top 50 原文链接:http://www.importnew.com/12773.html   本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎 ...

  9. Java线程面试题 Top 50(转载)

    原文链接:http://www.importnew.com/12773.html 本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入Java小组.转载请参见文章末尾的 ...

  10. 【转载】Java线程面试题 Top 50

    Java线程面试题 Top 50 2014/08/21 | 分类: 基础技术 | 4 条评论 | 标签: 多线程, 面试题 分享到:140 本文由 ImportNew - 李 广 翻译自 javare ...

随机推荐

  1. C++ Knowledge series 4

    Programming language evolves always along with Compiler's evolvement The Semantics of Function C++ s ...

  2. u-boot分析(十)----堆栈设置|代码拷贝|完成BL1阶段

    u-boot分析(十) 上篇博文我们按照210的启动流程,分析到了初始化nand flash,由于接下来的关闭ABB比较简单所以跳过,所以我们今天按照u-boot的启动流程继续进行分析. 今天我们会用 ...

  3. [topcoder]SRM 647 DIV 2

    第一题,送分题. 第二题, #include <vector> #include <algorithm> #include <map> #include <q ...

  4. April 12 2017 Week 15 Wednesday

    Genius often betrays itself into great errors. 天才常被天才误. Genius can help us get greater achievements, ...

  5. 每天备份NAS上的www目录到一块单独的硬盘上

    #!/bin/bash DATE=`date -d "now" +%Y%m%d` dataBackupDir=/media/2a76a963-92b1-4f74-a2c8-b7dc ...

  6. MYSQL 之SET GLOBAL innodb_buffer_pool_size =n

    工作遇到一个情况是索引相同的情况下,mysql服务在linux上运行很快,在windows服务器上运行很慢,版本是V5.7以后得版本,同事查找了下说应该设置 SET GLOBAL innodb_buf ...

  7. 2019.03.16 ZJOI2019模拟赛 解题报告

    得分: \(100+27+20=147\)(\(T1\)巨水,\(T2,T3\)只能写暴力分) \(T1\):深邃 比较套路的一眼题,显然是一个二分+贪心,感觉就是\(NOIP2018Day1T3\) ...

  8. 【转】在程序中设置android:gravity 和 android:layout_Gravity属性

    在进行UI布局的时候,可能经常会用到 android:gravity  和 android:layout_Gravity 这两个属性. 关于这两个属性的区别,网上已经有很多人进行了说明,这边再简单说一 ...

  9. sql查询语句面试题

    几个表 employees 表: EMPLOYEE_ID              NUMBER(6) FIRST_NAME                VARCHAR2(20) LAST_NAME ...

  10. ztree3.5中checkbox无法取消选中的问题解决

    使用jquery的tree插件ztree,用到复选框的功能 var setting = { check: { enable: true }, data: { simpleData: { enable: ...