4)public void remove():移除此线程局部变量当前线程的值。若是此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法从新初始化其值。这将致使在当前线程屡次调用 initialValue 方法。 html
下面是一个使用 ThreadLocal 的例子,每一个线程产生本身独立的序列号。就是使用ThreadLocal存储每一个线程独立的序列号复本,线程之间互不干扰。package sync; public class SequenceNumber { // 定义匿名子类建立ThreadLocal的变量 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { // 覆盖初始化方法 public Integer initialValue() { return 0; } }; // 下一个序列号 public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn) { this.sn = sn; } // 线程产生序列号 public void run() { for (int i = 0; i < 3; i++) { System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]"); } } } /** * @param args */ public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); // 三个线程产生各自的序列号 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } }程序的运行结果以下:
thread[Thread-1] sn[1] thread[Thread-1] sn[2] thread[Thread-1] sn[3] thread[Thread-2] sn[1] thread[Thread-2] sn[2] thread[Thread-2] sn[3] thread[Thread-0] sn[1] thread[Thread-0] sn[2] thread[Thread-0] sn[3]
ThreadLocal和线程同步机制相比有什么优点呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。
在同步机制中,经过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析何时对变量进行读写,何时须要锁定某个对象,何时释放对象锁等繁杂的问题,程序设计和编写难度相对较大。 而 ThreadLocal 则从另外一个角度来解决多线程的并发访问。ThreadLocal 会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。由于每个线程都拥有本身的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,能够把不安全的变量封装进 ThreadLocal。
归纳起来讲,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal 采用了“以空间换时间”的方式。前者仅提供一份变量,让不一样的线程排队访问,然后者为每个线程都提供了一份变量,所以能够同时访问而互不影响。
须要注意的是 ThreadLocal 对象是一个本质上存在风险的工具,应该在彻底理解将要使用的线程模型以后,再去使用 ThreadLocal 对象。这就引出了线程池(thread pooling)的问题,线程池是一种线程重用技术,有了线程池就没必要为每一个任务建立新的线程,一个线程可能会屡次使用,用于这种环境的任何 ThreadLocal 对象包含的都是最后使用该线程的代码所设置的状态,而不是在开始执行新线程时所具备的未被初始化的状态。 那么 ThreadLocal 是如何实现为每一个线程保存独立的变量的副本的呢?经过查看它的源代码,咱们会发现,是经过把当前“线程对象”看成键,变量做为值存储在一个 Map 中。 java
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。概括了两点:
一、每一个线程中都有一个本身的ThreadLocalMap类对象,能够将线程本身的对象保持到其中,各管各的,线程能够正确的访问到本身的对象。
二、将一个共用的ThreadLocal静态实例做为key,将不一样对象的引用保存到不一样线程的ThreadLocalMap中,而后在线程执行的各处经过这个静ThreadLocal实例的get()方法取得本身线程保存的那个对象,避免了将这个对象做为参数传递的麻烦。 程序员
Synchronized仍是ThreadLocal? web
ThreadLocal以空间换取时间,提供了一种很是简便的多线程实现方式。由于多个线程并发访问无需进行等待,因此使用ThreadLocal 会得到更大的性能。虽然使用ThreadLocal会带来更多的内存开销,但这点开销是微不足道的。由于保存在ThreadLocal中的对象,一般都是比较小的对象。另外使用ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。可是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每个线程都提供了变量的副本,使得每一个线程在某一时间访问到的并非同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通讯时可以得到数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
固然ThreadLocal并不能替代synchronized,它们处理不一样的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。 安全
参考: 多线程
http://my.oschina.net/huangyong/blog/159725
http://my.oschina.net/huangyong/blog/159489
http://www.itokit.com/2012/0817/74676.html
http://www.java3z.com/cwbwebhome/article/article20/200026.html?id=4841 并发