volatile 与 ThreadMap 区别及用法
volatile 关键字
-
作用:
- volatile 关键字用于声明一个变量,它确保了该变量在多线程环境下的可见性和有序性。
- 可见性:当一个线程修改了volatile变量的值时,其他线程能够立即看到这个修改的结果,无需通过显式同步(如synchronized)来实现。这是因为volatile变量的写操作会强制刷新到主内存,并且读操作也会始终从主内存中读取最新的值。
- 有序性:编译器和CPU的指令重排序优化不能违反volatile变量的操作顺序,这有助于保持多线程环境下的程序执行顺序的一致性。
- volatile 关键字用于声明一个变量,它确保了该变量在多线程环境下的可见性和有序性。
-
不保证原子性:
单独的volatile变量读/写操作是原子的,但复合操作(例如递增或递减)不是原子性的。即使变量被volatile修饰,也不能防止多个线程同时对其操作造成的数据不一致性问题。
-
适用场景:
- 常用于表示状态标志、中间状态标志、或者其他只需要保证可见性和有序性,而不涉及复合操作的状态变量。
ThreadLocal 类
- 作用:
- ThreadLocal 类提供了线程局部变量。每个线程都有自己的ThreadLocal实例副本,各线程间互不影响。
- 数据隔离:ThreadLocal变量在每个线程内部都有自己独立的副本,因此线程间的数据是完全隔离的,不会发生数据竞争。
- 避免同步开销:由于每个线程使用各自的副本,因此在多线程环境下,使用ThreadLocal可以减少甚至消除因共享数据带来的同步开销。
- ThreadLocal 类提供了线程局部变量。每个线程都有自己的ThreadLocal实例副本,各线程间互不影响。
- 工作原理:
- ThreadLocal内部维护了一个ThreadLocalMap,该映射表的键是ThreadLocal对象本身,值是每个线程绑定的变量副本。因此,每当线程访问ThreadLocal变量时,都会得到与当前线程绑定的专属值。
- 适用场景:
- 适用于那些需要在线程内部维持独立状态,且这个状态与其他线程无关的场景,例如每个线程的事务ID、用户登录信息、数据库连接、线程特定的日志记录器等。
示例代码
package com.gbl.demo.util;
import com.google.common.collect.Maps;
import java.util.Map;
/**
* @Author: dx
* @Date: 2024/3/14 17:51
* @Description: 线程工具示例类
*/
public class ThreadUtilDemo {
// volatile 线程计步器
volatile static int threadStep = 0;
// 线程1
public static Thread fistThread;
// 线程2
public static Thread secondThread;
// ThreadLocal 对象
public static ThreadLocal<Map<String, Integer>> threadLocalMap = new ThreadLocal<>();
static {
// 线程一实例化
fistThread = new Thread(() ->