保障线程安全的设计技术

Java 运行时存储空间

1、可以分为:栈区、堆区、方法区(非堆空间)

2、栈空间

(1)Stack Space

(2)为线程的执行准备一段固定大小的存储空间,每个线程都有独立的线程栈空间,创建线程时就为线程分配栈空间

(3)在线程栈中每调用一个方法,就给方法分配一个栈帧

(4)栈帧用于存储方法的局部变量,返回值等私有数据,即局部变量存储在栈空间中,基本类型变量、引用类型变量值也是存储在栈空间中,引用对象存储在堆中

(5)由于线程栈是相互独立的,一个线程不能访问另外一个线程的栈空间,因此,线程对局部变量、只能通过当前线程的局部变量,才能访问对象进行的操作,具有固定的线程安全性

3、堆空间

(1)Heap Space

(2)存储对象

(3)在 JVM 启动时,分配的一段以动态扩容的内存空间

(4)创建对象时,在堆空间中给对象分配存储空间,实例变量存储在堆空间中

(5)堆空间是多个线程之间可以共享的空间,因此实例变量可以被多个线程共享

(6)多个线程同时操作实例变量可能存在线程安全问题

4、非堆空间

(1)Non-Heap Space

(2)存储常量,类的元数据等

(3)非堆空间在 JVM 启动时,分配的一段可以动态扩容的存储空间

(4)类的元数据包括静态变量,类中方法,方法的元数据(方法名,参数,返回值等)

(5)多个线程可以共享非堆空间,因此访问非堆空间中的静态变量可能存在线程安全问题

 

无状态对象

1、对象就是数据及对数据操作的封装

(1)对象所包含的数据称为对象的状态(State)

(2)实例变量、静态变量称为状态变量

2、如果一个类的同一个实例,被多个线程共享,并不会使这些线程存储共享的状态,则该类的实例就称为无状态对象(Stateless Object)

3、如果一个类的实例,被多个线程共享,会使这些线程存在共享状态,则该类的实例称为有状态对象

4、实际上,无状态对象就是不包含任何实例变量,也不包含任何静态变量的对象

 

不可变对象

1、指一经创建它的状态就保持不变的对象,不可变对象具有固有的线程安全性。

2、当不可变对象现实实体的状态发生变化时,系统会创建一个新的不可变对象,如:String 字符串对象

3、一个不可变对象需要满足以下条件

(1)类本身使用 final 修饰,防止通过创建子类来改变它的定义

(2)所有的字段都是 final 修饰,final 字段在创建对象时必须显示初始化,不能被修改

(3)如果字段引用其他状态可变的对象(集合,数组),则这些字段必须是 private

4、应用场景

(1)被建模对象的状态变化不频繁

(2)同时对一组相关数据进行写操作,可以应用不可变对象,既可以保障原子性,也可以避免锁的使用

(3)使用不可变对象作为安全可靠的 Map key,如果 HashMap 的 key 是一个不可变对象,则 hashCode() 的返回值恒定,存储位置是固定的

 

线程特有对象

1、保障对非线程安全对象的访问的线程安全,避免锁的开销

2、线程特有对象也具有固有的线程安全性

3、ThreadLocal 类相当于线程访问其特有对象的代理,即各个线程通过 ThreadLocal 对象,可以创建并访问各自的线程特有对象

(1)一个线程可以使用不同的 ThreadLocal 实例,创建并访问不同的线程特有对象 

(2)ThreadLocal 实例为每个访问它的线程,都关联一个该线程特有的对象,ThreadLocal 实例都有当前线程与特有实例之间的一个关联

 

装饰器模式

1、基本思想

(1)为非线程安全的对象,创建一个相应的线程安全的外包装对象

(2)客户端代码不直接访问非线程安全的对象,而是访问它的外包装对象

(3)外包装对象、非线程安全对象具有相同的接口,即外包装对象的使用方式,与非线程安全对象的使用方式相同

(4)外包装对象内部通常会借助锁,以线程安全的方式,调用相应的非线程安全对象的方法

2、java.util.Collections 的 synchronizedXXX(xxx)

(1)可以把不是线程安全的 xxx 集合,转换为线程安全的集合

(2)返回值就是指定集合的外包装对象

(3)这类集合又称为同步集合

posted @   半条咸鱼  阅读(19)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示