Java静态块线程安全

Java静态块线程安全,java,multithreading,Java,Multithreading,我正在研究Java11并发模型,我发现可以通过以下方式获得真正的单例。该页特别指出: 由于JLS保证类初始化阶段是 顺序的,即非并发的,不需要进一步的同步 必需的 我知道静态字段只按顺序初始化一次(所以 公共类数据库查询{ 私有静态映射数据库=new HashMap(); 公共静态映射getDatabase(){ 返回集合。不可修改的映射(数据库); } 静止的{ database.put( DatabaseActions.LIST_CHIHUAHUA, “按数据描述从奇瓦瓦订单中选择id、no

我正在研究Java11并发模型,我发现可以通过以下方式获得真正的单例。该页特别指出:

由于JLS保证类初始化阶段是 顺序的,即非并发的,不需要进一步的同步 必需的

我知道静态字段只按顺序初始化一次(所以

公共类数据库查询{
私有静态映射数据库=new HashMap();
公共静态映射getDatabase(){
返回集合。不可修改的映射(数据库);
}
静止的{
database.put(
DatabaseActions.LIST_CHIHUAHUA,
“按数据描述从奇瓦瓦订单中选择id、nome、immagine”
);
//更多。。。
}
}
上面的代码是线程安全的吗?即使我有一个静态块和一个单独的静态初始化映射


我的答案是:

Java保证静态类初始化是线程安全的

上面我有一个静态块和一个静态变量,这有什么区别吗?都是在类启动时初始化的吗

所以我的问题是,如果静态块和静态变量(静态块之外)都保证不会导致多线程问题

即使我有一个静态块和一个单独的静态初始化映射

这显示了一种错误的心态。你没有单独的初始化

代码

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 = new HashMap<>();
  static {
    database.put(
      DatabaseActions.LIST_CHIHUAHUA,
      "SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
    );
  }
}

初始化/执行所有静态成员后,该类将被视为“已初始化”。在您的情况下,即
数据库
静态{}
。这是单线程完成的,其他任何操作都无法访问新初始化的类

之后,Java内存模型保证,尽管缺少显式同步,在初始化类之前完成的所有更改对之后发生的所有操作都是可见的(与构造函数初始化的字段类似)

这并不意味着它是线程安全的,因为
数据库
是一个可变对象。如果您指定的类是所有的类,那么光是它还不能保证没有外部实体可以访问
数据库
(想想反射)


使此线程安全的最佳方法是将
集合的结果存储在static字段中。不可修改映射(…)

初始化/执行所有静态成员后,该类被视为“已初始化”。在您的情况下,这是
数据库
静态{}
。这是单线程完成的,其他任何操作都无法访问新初始化的类

之后,Java内存模型保证,尽管缺少显式同步,在初始化类之前完成的所有更改对之后发生的所有操作都是可见的(与构造函数初始化的字段类似)

这并不意味着它是线程安全的,因为
数据库
是一个可变对象。如果您指定的类是所有的类,那么光是它还不能保证没有外部实体可以访问
数据库
(想想反射)

使此线程安全的最佳方法是在静态字段中存储
集合的结果。不可修改映射(…)

Read获取安全初始化的详细说明Read获取安全初始化的详细说明
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"
    );
  }
}
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
  }
}