我正在构建一个将ThreadLocal作为实例变量的单例,这个单例有一个可以被多个线程访问的方法,并且它被懒惰地实例化。现在我正在考虑这样的事情:
static final ThreadLocal<HashMap> bindingContext = new ThreadLocal<HashMap>();
但是我不确定这是不是一个好主意,我也可以选择让它成为一个实例变量,因为我正在使用它(正如我在单身人士所说的那样)。
所以问题是,初始化该类变量的最佳位置在哪里,或者它应该是一个类变量?
答案 0 :(得分:4)
保证静态初始化器以线程安全的方式执行。 JLS特别提到了这一点:
因为Java编程语言是多线程的,所以初始化 一些类或接口需要仔细同步,因为有些 其他线程可能正在尝试初始化相同的类或接口 同时。初始化也有可能 可以递归地请求类或接口作为其一部分 初始化该类或接口;例如,一个变量 A类中的初始化程序可能会调用不相关的B类的方法, 这可能反过来调用A类的方法。执行 Java虚拟机负责照顾 使用以下内容进行同步和递归初始化 过程
请参阅详细描述此内容的12.4.2 of JLS部分。
编辑:你正在尝试的非常好。来自ThreadLocal的javadoc:
ThreadLocal实例通常是类中的私有静态字段 希望将状态与线程相关联(例如,用户ID或 交易ID)。
答案 1 :(得分:1)
静态成员将确保将创建新的ThreadLocal,但每个新线程的ThreadLocal的初始值将为null。您可以通过覆盖initialValue()方法轻松提供特定于线程的初始值。一种方法是使用匿名内部类E.G.
static final ThreadLocal<HashMap> bindingContext = new ThreadLocal<HashMap>() {
@Override protected HashMap initialValue() {return new HashMap();}
};
答案 2 :(得分:0)
使用Lamda时,我们可以这样写:
private ThreadLocal<Map<String,String>> bindingContext = ThreadLocal.withInitial(HashMap::new);