Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对不可修改映射的并发访问 @Singleton @本地豆 @启动 @ConcurrencyManagement(ConcurrencyManagementType.BEAN) 公共类投递商HolderSingleton{ 私人易变地图递送者; @施工后 私有void init(){ Map deliverresmod=new HashMap(); for(字符串传递名称:传递名称){ /*按名称获取交付者*/ DeliverMod.put(DeliverName,Deliver); } deliveriers=Collections.unmodifiableMap(deliveriersmod); } 公共传递器getDeliver(字符串deliverName){ 返回送货人。获取(送货人名称); } @时间表(分钟=“*”,小时=“*”) 公共空间维护(){ init(); } }_Java_Jakarta Ee_Concurrency_Unmodifiable - Fatal编程技术网

Java 对不可修改映射的并发访问 @Singleton @本地豆 @启动 @ConcurrencyManagement(ConcurrencyManagementType.BEAN) 公共类投递商HolderSingleton{ 私人易变地图递送者; @施工后 私有void init(){ Map deliverresmod=new HashMap(); for(字符串传递名称:传递名称){ /*按名称获取交付者*/ DeliverMod.put(DeliverName,Deliver); } deliveriers=Collections.unmodifiableMap(deliveriersmod); } 公共传递器getDeliver(字符串deliverName){ 返回送货人。获取(送货人名称); } @时间表(分钟=“*”,小时=“*”) 公共空间维护(){ init(); } }

Java 对不可修改映射的并发访问 @Singleton @本地豆 @启动 @ConcurrencyManagement(ConcurrencyManagementType.BEAN) 公共类投递商HolderSingleton{ 私人易变地图递送者; @施工后 私有void init(){ Map deliverresmod=new HashMap(); for(字符串传递名称:传递名称){ /*按名称获取交付者*/ DeliverMod.put(DeliverName,Deliver); } deliveriers=Collections.unmodifiableMap(deliveriersmod); } 公共传递器getDeliver(字符串deliverName){ 返回送货人。获取(送货人名称); } @时间表(分钟=“*”,小时=“*”) 公共空间维护(){ init(); } },java,jakarta-ee,concurrency,unmodifiable,Java,Jakarta Ee,Concurrency,Unmodifiable,Singleton用于存储数据。数据每分钟更新一次。 是否可能,从不可修改的映射读取会导致同步出现问题?是否有可能在init方法中重新排序,并发布到集合的链接,但集合未完全填充?此处的线程安全问题: 从HashMap多次读取-是线程安全的,因为只要不修改集合,就允许多次读取,并且不会写入HashMap,因为该映射是不可修改的映射() 在交付程序上读/写是线程安全的,因为所有java引用分配都是原子的 我在这里看不到线程不安全的操作 我想指出的是,init()metod的名称有误导性,它表明在

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

此处的线程安全问题:

  • 从HashMap多次读取-是线程安全的,因为只要不修改集合,就允许多次读取,并且不会写入HashMap,因为该映射是
    不可修改的映射()

  • 交付程序上读/写是线程安全的,因为所有java引用分配都是原子的

我在这里看不到线程不安全的操作


我想指出的是,
init()
metod的名称有误导性,它表明在初始化过程中只调用了一次;我建议将其称为
rebuild()
recreate()

,Java内存模型保证了这一点。换句话说,如果您写入一个volatile变量并随后读取该变量,那么即使涉及多个线程,您也可以保证写入操作是可见的:

对易失性字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前

它更进一步,并保证在写入操作之前发生的任何操作也将在读取点可见(这要归功于程序顺序规则以及“发生在之前”关系是可传递的这一事实)

您的
getDeliveriers
方法从volatile变量中读取,因此它将看到在
Deliveriers=Collections.unmodifiableMap(deliverierMod)行上操作的最新写操作以及填充映射的前面操作


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

根据此处找到的重新排序网格,第一个操作是
普通存储
,第二个操作是
易失性存储
,因此在您的情况下,只要不可变映射不是null,就不会有任何重新排序问题


另外,在volatile存储之前发生的所有写入操作都将可见,因此您不会看到任何发布问题。

我想关键问题是从
@PostConstruct
方法返回的数据是否是在那里设置的数据的“安全发布”。如果我们假设不是,那么半构造的bean将被公开,这将是一个相当大的设计缺陷,会在多个地方咬到你。
deliverier
的易变性会阻止重新排序,你的类应该按预期工作(假设按名称获取deliverier是一个线程安全的操作)。由于重新排序,引用是否可能在集合初始化之前发布?@shurik2533如果发布了,我相信编程没有任何意义-@Dariusz有一些重新排序不会影响单线程模式下的执行,但会影响多线程程序。例如,移动
deliveriers=Collections.unmodifiableMap(deliveriersmod)在循环之前。@Dariusz不是真的-不可修改的映射是原始映射上的视图。如果更改原始地图本身,则不可修改的地图也将反映更改。@assylias您对地图的看法是正确的。我仍然认为
unmodifiableMap()
方法调用不能在循环之前被重新排序。如果该方法修改了地图怎么办?Java在编译时不可能知道这一点。
@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();
    }
}