Java并发编程 看不懂算我的!

ThreadLocal是什么

ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。ThreadLocal功能非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且ThreadLocal实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。

相信这里有很多学习java的朋友,小编整理了一份java方面的学习资料,

有想要学习java的可以加一下我的学习群的哟,60833,4068,欢迎爱学习java的你们!

ThreadLocal的接口方法

void set(Object value)

设置当前线程的线程局部变量的值;

public Object get()

该方法返回当前线程所对应的线程局部变量;

public void remove()

将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度;

protected Object initialValue()

返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的默认实现直接返回一个null

这里注意,ThreadLocal中是有一个Map,但这个Map不是我们平时使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类,不对外使用的。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,也就是说ThreadLocalMap中存的值是[ThreadLocal对象, 存放的值],这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量。

一个TheadLocal实例

/**

*

* @ClassName: SequenceNumber

* @author xingle

* @date 2015-3-9 上午9:54:23

*/

public class SequenceNumber {

//①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值

private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){

public Integer initialValue(){

return 0;

}

};

//②获取下一个序列值

public int getNextNum(){

seqNum.set(seqNum.get()+1);

return seqNum.get();

}

public static void main(String[] args){

SequenceNumber sn = new SequenceNumber();

//③ 3个线程共享sn,各自产生序列号

TestClient t1 = new TestClient(sn);

TestClient t2 = new TestClient(sn);

TestClient t3 = new TestClient(sn);

t1.start();

t2.start();

t3.start();

}

private static class TestClient extends Thread{

private SequenceNumber sn;

public TestClient(SequenceNumber sn){

this.sn = sn;

}

public void run(){

//④每个线程打出3个序列值

for (int i = 0 ;i<3;i++){

System.out.println("thread["+Thread.currentThread().getName()+"] sn["+sn.getNextNum()+"]");

}

}

}

}

通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量值,如①处所示。TestClient线程产生一组序列号,在③处,我们生成3个TestClient,它们共享同一个SequenceNumber实例。运行以上代码,在控制台上输出以下的结果:

每个线程所产生的序号虽然都共享同一个Sequence Number实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。

欢迎关注胖胖程序员,可视化学习java,每天更新文章,让Java学习更加简单。

猜你喜欢

转载自blog.csdn.net/weixin_44040460/article/details/85268530