并发访问unmodifiedMap

shu*_*533 4 java concurrency unmodifiable jakarta-ee

@Singleton
@LocalBean
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class DeliverersHolderSingleton {

    private volatile Map<String, Deliverer> deliverers;

    @PostConstruct
    private void init() {
        Map<String, Deliverer> deliverersMod = new HashMap<>();
        for (String delivererName : delivererNames) {
            /*gettig deliverer by name*/
            deliverersMod.put(delivererName, deliverer);
        }
        deliverers = Collections.unmodifiableMap(deliverersMod);
    }

    public Deliverer getDeliverer(String delivererName) {
        return deliverers.get(delivererName);
    }

    @Schedule(minute="*", hour="*")
    public void maintenance() {
        init();
    }
}
Run Code Online (Sandbox Code Playgroud)

单例用于存储数据。数据每分钟更新一次。从不可修改的映射中读取是否有可能会出现同步问题?是否有可能在 init 方法中发生重新排序,并且将发布到集合的链接,但集合未完全填充?

ass*_*ias 6

Java 内存模型保证对易失性变量的写入和后续读取之间存在先行发生关系。换句话说,如果您写入易失性变量并随后读取同一变量,则可以保证写入操作是可见的,即使涉及多个线程:

\n\n
\n

对易失性字段 (\xc2\xa78.3.1.4) 的写入发生在该字段的每次后续读取之前。

\n
\n\n

它更进一步,保证在写入操作之前发生的任何操作也将在读取点可见(感谢程序顺序规则以及发生之前关系是可传递的事实)。

\n\n

您的getDeliverers方法从 易失性变量中读取,因此它将看到该行上最新的写入操作deliverers = Collections.unmodifiableMap(deliverersMod);以及填充映射的先前操作。

\n\n

因此,您的代码是线程安全的,并且您的getDeliverers方法将根据地图的最新版本返回结果。

\n