Java内存模型中,程序(进程)拥有一块内存空间,能够被全部的线程共享,即MainMemory(主内存);而每一个线程又有一块独立的内存空间,即WorkingMemory(工做内存)。普通状况下,当线程须要对某一共享变量进行修改时,一般会进行以下的过程:html
1. 从主内存中拷贝变量的一份副本,并装载到工做内存中;算法
2. 在工做内存中执行代码,修改副本的值;安全
3. 用工做内存中的副本值更新主存中的相关变量值。多线程
以下图:并发
所谓“线程安全”,即多个线程同时执行同一段代码时,不会出现不肯定的或者与单线程条件下不一致的结果。一般,下列三种条件居其一的并发访问被JVM认为是线程安全的:.net
1. 有final关键字修饰且已被赋值;线程
2. 有volatile关键字修饰;htm
3. 有锁保护(synchronized、ReentrantLock等)。对象
第1点显而易见,再也不赘述。blog
volatile关键字的做用是告知JVM:它所修饰的域的原子操做都不须要通过线程的工做内存,而直接在主内存中进行修改。这样就保证了线程从主内存中读取(read)它的值的时候,老是最新的。可是,Java中的运算极少是原子的,即使是像++ 这样的一元运算符或者+= 这样的二元运算符都不是原子的,所以volatile关键字修饰的域在多线程环境下依然可能会读写出“脏”数据:它只保证每一步原子操做的线程安全,但不保证整个操做过程的线程安全。也所以,volatile主要被用于变量只有原子操做的场合,如赋值、移位等。
锁,不管是显式(ReentrantLock)仍是隐式(synchronized)的同步锁,或是信号量(Semaphore),抑或是阻塞队列(BlockingQueue),仍是其它的同步措施(CyclicBarrier、CountDownLatch、wait¬ify等),它们的做用都是同样的,就是保证一个共享变量的副本进入到某个线程的工做内存以后,该共享变量就再也不会被其它线程访问到,直到前述过程的第3步执行完成。
线程在有同步锁的状况下访问共享变量的过程以下:
1. 获取同步锁
2. 清空工做内存
3. 从主内存将拷贝变量副本,并装载到工做内存
4. 对副本执行代码
5. 用副本数据更新主内存中的相关变量
6. 释放同步锁
一般,没有得到同步锁的线程将被阻塞,直到它竞争到同步锁。这样,没有得到同步锁的线程不只不能访问数据,甚至都不能继续运行,因而强迫性地保证了线程安全。也所以,线程安全代码的开销要大于不安全的代码,同步锁的开销也要大于volatile。
上述线程运行的过程其实是JVM的思惟模型。JVM真正的逻辑内存模型以下图所示:
其中:
线程的工做内存位于JVM栈中。线程中的每一个方法在运行的时候都会在栈中申请一个帧(frame),用来保存变量表、操做集、动态连接、出入口等信息。每一个方法从调用到返回,就是它的帧在线程栈中从入栈到出栈的过程。
程序的主内存位于JVM堆。程序中的每个实例或数据域都会被分配到堆中,并由全部线程共享(若是有权限的话)。线程从主内存中拷贝变量副本的过程,就是从堆中读取(read)该变量的数据,而后在本身的栈中建立(load)一个新的实例。可见,load以后,栈中的操做就与堆中的变量没有关系了。
线程PC用于寄存每一个线程当前执行到的机器指令。本地方法栈用于调用JNI方法,并在方法调用结束后销毁。
Java的垃圾收集就是针对堆中的对象进行的。堆中按照对象的生命周期长短分为以下图的几个区域:
其中:
新生代(NewGeneration)分为两个区:Eden和Survivor;而Survivor区又分为了等大的两个区:S0和S1(或From和To)。新建立(new)的对象都会分配到Eden区中。当Eden区满时,会触发一次MinorGC,JVM会将Eden中存活的对象进行标记并拷贝到S0中,同时回收全部无效的对象。当S0满时,S0中存活的对象被拷贝到S1区,无效的对象被回收。当S1也满时,意味着整个新生代都满了,此时将触发一次MajorGC,新生代中部分存活的对象被标记后拷贝到老年代区中,无效的对象被回收,同时新生代中剩余的对象按必定的规则分配到Eden、S0、S1中。
老年代(OldGeneration)中保存的,是屡次GC以后仍然存活的对象。在老年代区中,若是剩余的任一连续内存空间都不足以容纳一个对象时,须要对老年代区进行碎片压缩,此时程序将挂起。当老年代满时,将触发一次FullGC,它先对新生代发起一次MinorGC,再在老年代区标记清除无效的对象。
持久代(PermanentGeneration)也就是前图中堆内部的方法区。这里存放了程序中每一个Class和ClassLoader以及一些常量的数据信息。其中又包含了常量池,用于保存常量数据、方法签名等在编译时就决定的不变量。持久代中一般极少、甚至不发生GC。
GC中的算法参见以下的连接:
http://www.cnblogs.com/aigongsi/archive/2012/04/06/2434771.html
http://www.cnblogs.com/aigongsi/archive/2012/04/13/2446166.html
转自:
http://blog.csdn.net/sadfishsc/article/details/10325879