0%

线程封闭

线程封闭

概念

当访问共享变量时,往往需要加锁来保证数据同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程中访问数据,就不需要同步了,这种技术称为线程封闭。

线程封闭技术有一个常见的应用,JDBC的Connection对象。Connection对象在实现的时候并没有对线程安全做太多的处理,JDBC的规范里也没有要求Connection对象必须是线程安全的。实际在服务器应用程序中,线程从连接池获取了一个Connection对象,使用完再把Connection对象返回给连接池,由于大多数请求都是由单线程采用同步的方式来处理的,并且在Connection对象返回之前,连接池不会将它分配给其他线程。因此这种连接管理模式处理请求时隐含的将Connection对象封闭在线程里面,这样我们使用的Connection对象虽然本身不是线程安全的,但是它通过线程封闭也做到了线程安全。

方法

Ad-hoc 线程封闭

Ad-hoc线程封闭是指,维护线程封闭性的职责完全由程序实现来承担。Ad-hoc线程封闭是非常脆弱的,因为没有任何一种语言特性,例如可见性修饰符或局部变量,能将对象封闭到目标线程上。事实上,对线程封闭对象(例如,GUI应用程序中的可视化组件或数据模型等)的引用通常保存在公有变量中。

堆栈封闭

堆栈封闭其实就是方法中定义局部变量。不存在并发问题。多个线程访问一个方法的时候,方法中的局部变量都会被拷贝一份到线程的栈中(Java内存模型),所以局部变量是不会被多个线程所共享的。

ThreadLocal线程封闭

它是一个特别好的封闭方法,其实ThreadLocal内部维护了一个mapmap的key是每个线程的名称,而map的value就是我们要封闭的对象ThreadLocal提供了getsetremove方法,每个操作都是基于当前线程的,所以它是线程安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//ThreadLocal的get方法源码
public T get() {
Thread t = Thread.currentThread();//当前线程对象
ThreadLocalMap map = getMap(t);//get操作基于当前线程
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

ThreadLocal的使用场景:

  • 实现单个线程单例以及单个线程上下文信息存储,比如交易id等
  • 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例
  • 承载一些线程相关的数据,避免在方法中来回传递参数