在进行get()之前,必须先进行set(),否则可能会报空指针异常
public class ThreadLocalNPE {
ThreadLocal threadLocal = new ThreadLocal();
public void set(){
threadLocal.set(Thread.currentThread().getId());
}
/**
* 这里的返回值使用long的时候,如果没有set()就调用get()那么会报空指针异常,因为牵涉到拆箱转换(将对象类型转换为基本类型)
* @return
*/
public Long get(){
return threadLocal.get();
}
public static void main(String[] args) {
ThreadLocalNPE threadLocalNPE = new ThreadLocalNPE();
System.out.println(threadLocalNPE.get());
new Thread(() -> {
threadLocalNPE.set();
long threadId = threadLocalNPE.get();
System.out.println(threadId);
}).start();
}
}
ThreadLocal拆装箱引起的空指针异常
public class SpringbootApplication {
/**
* 登录方法
*
* @param userId
*/
public void login(Integer userId) {
UserInfoHolder.userInfoHolder.set(userId);
System.out.println("用户登录了," + "保存用户id:" + userId);
order();
}
/**
* 下订单方法
*/
public void order() {
System.out.println("订单服务获取了用户id:" + UserInfoHolder.userInfoHolder.get() + ",下了订单");
logistics();
}
/**
* 物流方法
*/
public void logistics() {
UserInfoHolder.userInfoHolder.remove();
System.out.println("物流服务获取了用户id:" + UserInfoHolder.get() + ",发出了物流");
}
/**
* ThreadLocal
*/
static class UserInfoHolder {
private static ThreadLocal userInfoHolder = new ThreadLocal<>();
/**
* 自定义了一个get方法,返回int类型
*
* @return
*/
public static int get() {
return userInfoHolder.get();
}
}
public static void main(String[] args) throws Exception {
new SpringbootApplication().login(666);
}
}
报了空指针异常
看下原因:
以下是userInfoHolder.get()的get方法的源码:
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();
}
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;
}
protected T initialValue() {
return null;
}
可以发现它返回的是一个泛型T,而这个T的类型是在ThreadLocal初始化就定义好的了,同时如果没有做任何初始化赋值,或者设值操作,默认就会返回null
以下ThreadLocal类的定义:
public class ThreadLocal {
}
而上述测试代码中,初始化ThreadLocal时,定义的类型是Integer,所以get方法返回的也是Integer类型,由于调用了ThreadLocal的remove操作,所以默认会返回null,照理说返回null也没什么问题,关键就是方法里返回参数用的是int类型做接收,这样就会自动拆装箱,而由于值为null,自然就引起了空指针异常。返回值改为Integ返回er就ok了