什么是线程封闭?
当访问共享变量时,往往需要加锁来保证数据同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程中访问数据,就不需要同步了。这种技术称为线程封闭。在Java语言中,提供了一些类库和机制来维护线程的封闭性,例如局部变量和ThreadLocal类。
实现线程封闭的方法有哪些呢?
1、Ad-hoc线程封闭
Ad-hoc线程封闭是指,维护线程封闭性的职责完全有程序实现来承担。例如可见性修饰符或局部变量,能将对象封闭到目标线程上。事实上对于线程封闭对象通常保存在共有变量中。Ad-hoc线程封闭是非常脆弱的,所以程序中尽量少使用它,可以使用以下两种技术(栈封闭,ThreadLocal)。
2、栈封闭
栈封闭也被成为线程内部使用或者线程局部使用,不要与ThredaLocal混淆,比Ad-hoc更易于维护,也更加健壮。在栈封闭中,只能通过局部变量才能访问对象。
public void test(){ //定义一个变量 Set set ; // 实例化一个TreeSet对象,并将该对象的一个引用保存到set中。 set = new TreeSet(); }
这样TreeSet对象就被封闭在局部变量中,因此也被封闭到执行线程中,它位于执行线程的栈中,其他线程无法访问这个栈。
3、ThreadLocal类
维持线程封闭性的一种更为规范的方法是使用ThreadLocal,这个类能使线程中的某个值与保存值的对像关联起来,ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回由当前线程执行set时设置的最新值。ThreadLocal通常用于防止对可变对像的单实例变量或全局变量进行共享。
public abstract class TestThreadLocal { volatile static String name = "张三"; static ThreadLocal t = new ThreadLocal();//新建一个ThreadLocal对象 public static void main(String[] args) { //新建一个线程 new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } //获取属性的值 System.out.println(name); System.out.println(t.get()); } }).start(); //新建另一个线程 new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //改变属性的值 name="李四"; t.set("王五"); } }).start(); } }
运行结果
李四 null
Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作。因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有一个指向同一个ThreadLocal变量的引用,但是这两个线程依然不能看到彼此的ThreadLocal变量域。
注:本文为Wayne原创,未经许可不得在任何平台转载。如需转载,与作者联系~
欢迎加入java零基础交流:168449592,欢迎分享工作经验,提供技术支持解答。
关注微信公众号:技术训练营(微信ID:TechBootcamp),获取更多资讯~
微信扫一扫,发现更精彩。