Java多线程详解(八)------ ThreadLocal和InheritableThreadLocal

1 类ThreadLocal的使用

变量值的共享可以使用public static变量的形式,所有的线程都是用同一个public static变量。而ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放的盒子,盒子中可以存储每个线程的私有数据。

1.1 验证线程变量的隔离性
public class Tools {
    public static ThreadLocal<Date> t1 = new ThreadLocal<>();
}
public class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 20; i++) {
                if (Tools.t1.get() == null) {
                    Tools.t1.set(new Date());
                }
                System.out.println("A " + Tools.t1.get().getTime());
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadB extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 20; i++) {
                if (Tools.t1.get() == null) {
                    Tools.t1.set(new Date());
                }
                System.out.println("B " + Tools.t1.get().getTime());
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) {
        try {
            ThreadA threadA = new ThreadA();
            threadA.start();
            Thread.sleep(1000);
            ThreadB threadB = new ThreadB();
            threadB.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程threadAthreadB都向t1对象中set()数据值,但每个线程还是能取出自己的数据。

1.2 解决get()返回null问题
public class Tools {
    public static ThreadLocal<Date> t1 = new ThreadLocal<Date>() {
        @Override
        protected Date initialValue() {
            return new Date();
        };
    };
}
1.3 实现机制
  1. 每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocalMap,可以存放若干个ThreadLocal
ThreadLocal.ThreadLocalMap threadLocals = null;
  1. 当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocalvalue,否则进行初始化,初始化就是将initialValue的值setThreadLocal中。
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
  1. 当我们调用set()方法的时候,就是将值设置进ThreadLocal中。
  2. 总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。
  3. 应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal

2 类InheritableThreadLocal的使用

public class InheritableThreadLocal<T> extends ThreadLocal<T> {}

使用类InheritableThreadLocal可以在子线程中取得父线程继承下来的值。在继承的同时还可以对值进行进一步的处理。

public class InheritableThreadLocalExt extends InheritableThreadLocal<Long> {
    @Override
    protected Long initialValue() {
        return new Date().getTime();
    }

    @Override
    protected Long childValue(Long parentValue) {
        return parentValue * 2;
    }
}
);
    }

    @Override
    protected Long childValue(Long parentValue) {
        return parentValue * 2;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值