企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## Java专题十三(3):内存模型、volatile、ThreadLocal [TOC] ### JVM内存模型 ![](https://img.kancloud.cn/73/a0/73a0393e9246be62b1885c1123ae4af8_486x435.png) 在JVM中主要分为Thread Stack和Heap,每一个线程都会复制一份局部变量到自己的线程栈中,所以一个线程对局部变量的改变对另一个线程是不可见的 - 线程栈(Thread Stack):存储了所有方法内部的局部变量(包括基本数据类型和对对象的引用) - 堆区(Heap):存储了所有对象,成员变量(包括基本数据类型,且和所属对象一同存储在Heap中) ### 物理内存模型 ![](https://img.kancloud.cn/52/6a/526af1d03f57b6fc3d8b42a7aa800f20_452x398.png) 物理内存模型包括3层,`CPU`、`CPU Cache Memory`、`Main Memory`,操作数据的速度排序:`CPU` > `CPU Cache Memory` > `Main Memory`,这里的`Main Memory`就是我们所说的内存。 当一个线程修改共享数据时,需要先从`Main Memory`读取共享数据到`CPU Cache Memory`时,当然只要它没有写回到`Main Memory`,对共享数据的改变就不会让其它线程知道,即对其它线程时不可见的 ### volatile关键字 使用volatile关键字保证了对其它线程对变量写的可见性,具体表现如下 - 对volatile变量的每一次读取都是从`Main Memory`中读取的,而不是从`CPU Cache Memory`中读取的 - 对volatile变量的修改会马上写回到`Main Memory`中 如:`java.util.Thread`中声明的成员变量`private volatile String name;` ### ThreadLocal变量 `java.lang.ThreadLocal`是java提供的一个类,每个线程对`ThreadLocal`变量的读写操作(get和set方法)都保存着变量的一个副本,因此相对于其它线程来说是隔离互不影响的,但无法完成共享变量的操作,也就不存在所谓的线程安全问题 | 方法 | 寿命 | | --- | --- | | `void set(T value)`| 设置值 | | ` T get()` | 获取值 | | `T initialValue()`| 初始化值 | | `void remove()` | 移除值 | | `static <S> ThreadLocal<S> ` <br>` withInitial(Supplier<? extends S> supplier)` | 静态方法,初始化值 | 使用方法如下: ~~~ ThreadLocal<String> threadLocal = new ThreadLocal<String>(){ @Override protected String initialValue() { return ""; } }; // can use with follow method to initial value ThreadLocal<String> threadLocal1 = ThreadLocal.withInitial(new Supplier<String>() { @Override public String get() { return ""; } }); threadLocal.set("java"); threadLocal.get(); // "java" threadLocal.remove(); // remove "java" threadLocal.get(); // with initial value: "" ~~~