一、 java内存结构
Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。
1. Heap(堆):实例分配的地方,通过-Xms与-Xmx来设置(下图为heap的结构,详细参照 http://5007260.blog.51cto.com/blog/4997260/1324401)
2. MethodArea(方法区):类的信息及静态变量。 对应是Permanet Generation, 通过-XX:PermSize来设置
3. java的栈(局部变量区):虚拟机只会直接对Javastack执行两种操作:以帧为单位的压栈或出栈。通过-Xss来设置, 若不够会抛出StackOverflowError
4. ProgramCounter(PC寄存器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。
5. Nativemethodstack(本地方法栈):保存native方法进入区域的地址
当中Heap和MethodArea是被所有线程的共享使用的;
而Javastack,Programcounter和Nativemethodstack是以线程为粒度的,每个线程独自拥有自己的部分
二、 内存模型
由以上可以知道java内存分为main memory和线程的Working Memory,就会涉及到这两种内存数据同步以及多个线程操作时数据一致性和可见性的问题。这就不可避免要加锁了,在java中可采用如下的形式:
1. synchronized关键字或使用java.util.concurrent.locks中的锁
2. volatile关键字 Volatile表示的是线程每次操作都是在主内存中进行, 这只能保证其可见性, 而不能保证其的原子性, 要有原子性还得加锁
3. final变量(基本类型,类类型还是可以改值的)
三、 如何保证线程安全
1. 每个线程只操作自有的数据, 这个可能性要小。
2. 设计的类无数据成员, 也就没有共享变量, 要有可用是 final或volatile
3. 在操作共享变量时同步
转载于:https://blog.51cto.com/5007260/1324361