我正在研究 Java 11 并发模型,我发现可以通过 LazyHolder pattern 获得真正的单例。 .特别是,该页面说:
Since the class initialization phase is guaranteed by the JLS to be sequential, i.e., non-concurrent, no further synchronization is required...
好的,所以我明白静态字段只按顺序初始化一次(所以
public class DatabaseQueries {
private static Map<DatabaseActions, String> database = new HashMap<>();
public static Map<DatabaseActions, String> getDatabase() {
return Collections.unmodifiableMap(database);
}
static {
database.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
// more...
}
}
上面的代码线程安全吗?即使我有一个静态 block 和一个单独的 map 静态初始化!
我在 this 找到了回答:
Static class initialization is guaranteed to be thread-safe by Java.
上面我有一个静态 block 和一个静态变量,这有什么区别吗?是否都在类启动时初始化?
所以我的问题是静态 block 和静态变量(在静态 block 之外)是否都保证不会导致多线程问题
最佳答案
你写的
Even if I have a static block AND a separate static initialization of a map!
这表明错误的心态。您没有单独的初始化。
代码
public class DatabaseQueries {
private static Map<DatabaseActions, String> database = new HashMap<>();
static {
database.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
}
}
等同于
public class DatabaseQueries {
private static Map<DatabaseActions, String> database;
static {
database = new HashMap<>();
database.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
}
}
static
字段的所有初始化器(编译时常量除外)与所有 static {}
block 合并为一个初始化器,按照它们在类声明。
线程安全适用于单个结果初始化器的完成和初始化数据的后续读取。
所以如果映射在类初始化后从未被修改过,它就是线程安全的。没有必要,但强烈建议强制执行“初始化后不修改”规则:
public class DatabaseQueries {
private static final Map<DatabaseActions, String> database;
static { // keep variable declaration and initializer close for readability
Map<DatabaseActions, String> map = new HashMap<>();// mutable ref during initialization
map.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
// more...
database = Collections.unmodifiableMap(map);// enforce read-only
}
public static Map<DatabaseActions, String> getDatabase() {
return database;// no wrapping necessary, it’s already wrapped
}
}
关于Java静态 block 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58993352/