Java中的ThreadLocal

ThreadLocal是用于解决多线程程序的并发问题的工具类,早在java 1.2版本中就提供了java.lang.ThreadLocal。

java在语言层面上没有为线程局部变量提供支持,但是java利用ThreadLocal类来支持线程局部变量。

ThreadLocal是一个保存线程本地化对象的容器。当运行与多线程环境中的某个对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。所以每个线程都可以独立改变自己的副本,而不会影响其他线程所对应的副本。从线程的角度看,这个变量就像线程专有的本地变量。

InheritableThreadLocal继承于ThreadLocal,它自动为子线程复制一份从父线程那里继承而来的本地变量;在创建子线程时,子线程会接收所有可继承的线程本地变量的初始值。当必须将本地线程变量自动传送给所有创建的子线程时,应尽可能地使用InheritableThreadLocal而非ThreadLocal。

ThreadLocal接口方法

  • void set(Object value):设置当前线程的线程局部变量的值
  • public Object get():返回当前线程所对应的线程局部变量
  • public void remove():将当前线程局部变量的值删除,目的是为了减少内存的占用。该方法是java 5.0新增的。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显示调用该方法清除线程的局部变量并不是必需的操作,但它可以加快内存回收的速度。
  • protected Object initialValue():返回该线程局部变量的初始值。该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第一次调用get()或者set(Object)时才执行,并且仅执行一次。ThreadLocal中的默认实现直接返回一个null。

在java 5.0中,ThreadLocal已经支持泛型。

ThreadLocal实现局部变量方法

在ThreadLocal类中有一个Map,用于存储每个线程的变量副本,Map中元素的键为线程对象,值为对应线程的变量副本。

下面的例子是一个简单的ThreadLocal实现(在思路上与ThreadLocal非常相似)

public class SimpleThreadLocal{
    private Map valueMap = Collections.synchronizedMap(new HashMap());
    public void set(Object newValue){
        //键为线程对象,值为本线程的变量副本
        valueMap.put(Thread.currentThread(),newValue);
    }
    public Object get(){
        Thread currentThread = Thread.currentThread();
        //返回本线程对应的变量
        Object o = valueMap.get(currentThread); 
        //如果Map中不存在,则放入Map中保存
        if(o==null && !valueMap.containsKey(currentThread)){
            o=initialValue();
            valueMap.put(currentThread,o);
        }
        return o;
    }
    public void remove() {
        valueMap.remove(Thread.currentThread());
    }
    public Object initialValue() {
        return null;
    }

}

一个ThreadLocal实例

package com.jcl.base;

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(){
            //每个线程打印三个序列值
            for(int i=0;i<3;i++){
                System.out.println("thread["+Thread.currentThread().getName()+"] sn["+sn.getNextNum()+"]");
            }
        }
    }
    
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值