依旧不想说话..........我就是看到了ThreadLocal就写了。
参考:深入研究java.lang.ThreadLocal类 大大写的很好!我就挑了我喜欢的写了(✿◕‿◕✿)
一、ThreadLocal是啥啥
▶ThreadLocal是线程局部变量,它为每一个使用该变量的线程提供一个变量值的副本,每一个线程都可以独立的改变自己的副本,而不会和其他线程的副本发生冲突。
▶从线程的角度看,每个线程都保持一个对其线程局部变量副本的引用,只要线程是活动的并且ThreadLocal实例是可访问的,在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非其他地方还有引用)。
▶对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而不互相影响。
ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。
二、API
ThreadLocal() 创建一个线程本地变量。
T get() 返回此线程局部变量的当前线程副本中的值。
void set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。
protected T initialValue() 返回此线程局部变量的当前线程的初始值。
void remove() 移除此线程局部变量的值。
一个小例子(Student类就不写了........name,age加上get 和set 方法)
public class ThreadLocalDemo implements Runnable { private static final ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] args) { ThreadLocalDemo td = new ThreadLocalDemo(); Thread t1 = new Thread(td,"a"); Thread t2 = new Thread(td,"b"); t1.start(); t2.start(); } @Override public void run() { accessStudent(); } public void accessStudent(){ String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName + " is Running"); Random random = new Random(); int age = random.nextInt(20); Student student = getStudent(); student.setAge(age); System.out.println("thread " + currentThreadName + "first read age is: " + student.getAge()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread " + currentThreadName + "second reead age is: " + student.getAge()); } protected Student getStudent(){ //获取本地线程变量并强制转换为Student类型 Student student = (Student) studentLocal.get(); //线程首次执行此方法的时候studentLocal.get() 肯定为null if(student == null){ student = new Student(); studentLocal.set(student); } return student; } }
结果就是两个线程的age不一样,但在不同时刻打印的值是一样的。
三、总结
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题,不能使用原子类型,只能使用Object类型。
Synchronized是利用锁的机制,某一时刻只能被一个线程访问,而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象。