我对如何使用ThreadLocal
提出了疑问。
背景和情境
有几个单例对象使用ThreadLocal
为每个线程创建一个副本。该单例对象具有函数foo()
。
public class SingletonA {
protected static ThreadLocal<SingletonA> singleton = new ThreadLocal<SingletonA>() {
@Override
protected SingletonA initialValue() {
return new SingletonA();
}
};
private SingletonA() { ... }
public static SingletonA getInstance() { return singleton.get(); }
public static void remove() { singleton.remove(); }
public static void foo() { ... }
}
......有SingletonB,SingletonC等等。
有一个单例存储库可以缓存上面的ThreadLocal
单例。这个类也是ThreadLocal
单例 -
public class SingletonRepo {
protected static ThreadLocal<SingletonRepo> singleton = new ThreadLocal<SingletonRepo>() {
@Override
protected SingletonRepo initialValue() {
return new SingletonRepo();
}
};
private SingletonRepo() { ... }
public static SingletonRepo getInstance() { return singleton.get(); }
public static void remove() { singleton.remove(); }
public SingletonA singletonA;
// same thing for singletonB, singletonC, ...
public static init() {
// Caching the ThreadLocal singleton
singletonA = SingletonA.getInstance();
// Same thing for singletonB, singletonC ...
}
}
这是我目前通过ThreadLocal
SingletonRepo
单身人士的方式
public class App {
public SingletonRepo singletonRepo;
public static void main(String [] args) {
singletonRepo = SingletonRepo.getInstance();
singletonRepo.init();
singletonRepo.singletonA.helperFunction();
}
}
问题
正如您在上面的上下文中看到的,为了访问ThreadLocal
单身人士,我首先将其缓存在SingletonRepo
中。当我需要使用ThreadLocal
单例时,我从缓存引用中获取它。我有以下问题 -
ThreadLocal
单例是不好的做法吗?ThreadLocal
(为Singleton对象调用SingletonA.getInstance()
)始终访问get()
单例是否为更好的做法?答案 0 :(得分:1)
线程本地缓存副本很好,因为它更简单,更高效。一个缓存副本,你不确定它是本地线程可能是一个问题。
单身定义意味着只能有一个。我不会把你作为一个单身人所拥有的,每个线程都有一个。
我会在它的构造函数中初始化()你的线程局部对象。
BTW你的ThreadLocal应该是private static final
我怀疑。
答案 1 :(得分:0)
目标还不是很清楚。 ThreadLocal
查找的性能方面可以忽略不计,因此“缓存”一个值没有多大意义,尤其是当您仍然需要查找缓存实例时。
如果SingletonA
,SingletonB
,SingletonC
等类型没有ThreadLocal
,那么SingletonRepo
是唯一的,那么它会更有用实例通过ThreadLocal
维护,而其他实例由SingletonRepo
维护,因此隐式线程本地。但是,为了以这种方式实现,SingletonA
,SingletonB
,SingletonC
等的构造函数必须由SingletonRepo
访问。
鉴于您目前实现它的方式,让我印象深刻的是单例类和repo类上存在remove
方法,因此允许不一致。例如,我可以调用SingletonRepo.getInstance().init()
,然后调用SingletonA.remove()
和etvoilà您已创建当前线程的情况,其中SingletonRepo.getInstance().singletonA
包含对实例的引用,SingletonA.singleton
不保持一个值,并在下一次调用getInstance()
时创建一个新实例,以便同一个线程同时存在两个不同的实例。