您的位置:首页 > 其它

线程安全解析(附带JVM内存结构和锁机制说明)

2018-01-23 00:00 399 查看
摘要: 线程安全这块的之前没有好好总结,这里加上自己的理解,欢迎大家及时修正

一、JVM内存结构和保存的变量属性(JVM调优和算法不涉及)

1.堆、栈、方法区、程序计数器、本地方法栈--重点说堆、栈、方法区,本篇的讲解不涉及垃圾回收

堆:通过new关键字创建的对象的信息

栈:基本类型、堆中对象的引用、局部变量

方法区:static修饰静态变量、final常量、.class文件

2.其中堆和方法区属于被程序共享、里面的变量信息涉及到多线程访问的操作安全性,栈内存不做讲解、因为每次HTTP请求都会为当前线程分配独立的栈内存,请求执行完成、占内存会自动销毁释放空间,不涉及GC回收、属于线程独享的,栈内存中的信息属于线程安全

二、对于线程安全控制常用的方式ThreadLocal、Lock、Atomic工具包、Synchronized

1.ThreadLocal:对于每次的操作都会创建一个本地变量副本,该变量副本是从主存中读取的最新的数据,单独的变量副本之间是相互独立的,互不影响,而且ThreadLocal修饰的变量都是当前线程私有的,从性能上说是以空间换时间,对内存消耗比较大,但是效率好

2.Lock和Synchronized:这两者使用锁机制来实现操作安全控制,作用的粒度都很小,区别是前者是要手动关掉锁,如果有资源相互占用的情况下死锁的情况会出现,而且对性能影响比较大

3.Atomic提供的对变量的操作AtomicInteger、AtomicBoolean、AtomicLong...,使用ACS机制实现,属于一种无锁操作状态,类似于指令集的操作,性能上面效果较好

三、内存结构和锁有了了解之后主要涉及的就是方法区和堆区的变量操作,如何操作保证其安全性

1.多例模式下

大家常用的springMVC和struts2对比可以知道,struts2创建的对象是多例模式,每次的HTTP请求都会单独的创建对象,当前的线程操作独有的,所以是线程安全的,struts2整合spring时对象交给spring管理所以一般scope属性会设置为prototype,但是要注意的是多例模式的安全性设计的是非static变量,如果涉及到static修饰的变量,该变量在JVM加载的时候是在方法区保存,所以多线程情况下不是线程安全的,变量可以用ThreadLocal来修饰,变为线程私有属性保证操作安全性

2.单例模式下:

2.1:单例:有状态和无状态bean

2.1.1:无状态bean是线程安全的、比如service、dao、对象的状态初始化的时候不会发生改变

2.1.2:有状态的bean非线程安全的,涉及到保存操作

2.2:单例模式下创建的对象多次调用都是同一个,所以属于程序共享的,这里就涉及到线程安全,所以单例模式下的变量不管是static修饰还是非static都不是线程安全的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: