为了线程安全,必须同步哪些映射方法?

时间:2019-02-20 07:32:45

标签: java multithreading synchronization

我有一个包含映射的类,可以从多个线程同时访问此映射。

我按如下方式创建班级:

@Autowired
public Scheduler() {
    this.scheduledRunnables = Collections.synchronizedSortedMap(new TreeMap<Integer, Runnable>());
}

因此,根据documentation,为确保此方法正常运行,我必须遵循以下准则:

  

返回由指定排序映射支持的同步(线程安全)排序映射。为了保证串行访问,至关重要的是所有对后备排序映射的访问都必须通过返回的排序映射(或其视图)来完成。    至关重要的是,用户在遍历其任何集合视图或其子视图,headMap或tailMap视图的任何集合视图时,必须手动对返回的排序后的地图进行同步。

我问这个问题是因为我不确定我是否完成了手动同步部分,或者是否不必要地使用了该块。

我正以两种不同的方式访问此地图。

访问最低键值

因此,我99%确信我应该使用同步块,因为这是访问迭代器时文档中的一个示例。

public int getNextAvailableExecutionOrder() {
    synchronized (scheduledRunnables) {
        if (scheduledRunnables != null && scheduledRunnables.size() > 0) {
            return scheduledRunnables.keySet().stream().min(Comparator.comparing(Integer::valueOf)).get() + 1;
        }
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
}

添加新的可运行物品

我对此不确定。是在这里访问地图迭代器,还是可以在没有同步块的情况下安全地放入新项目?

protected void scheduledNewTask(final int order, final Runnable task) {
    LOG.info("Added new scheduled task {} with order {}", taskName, order);
    synchronized (scheduledRunnables) {
        scheduledRunnables.put(order, task);
    }
}

编辑

以上是我当前的实现方式,但它似乎无法按我的意愿运行:

2019-02-20 08:33:39.080  INFO 32082 --- [       Thread-6] s.i.s.a.gatemaster.SchedulingSupport     : Added new scheduled task Log upload with order -2147483648
2019-02-20 08:33:39.838  INFO 32082 --- [tHubReceiveTask] s.i.s.a.gatemaster.SchedulingSupport     : Added new scheduled task Firmware update (1.9.1) with order -2147483648

1 个答案:

答案 0 :(得分:1)

如果仅在您发布/访问地图的两种情况下发布此信息,则您无需通过 Collections.synchronizedSortedMap 用同步包装器包装地图,因为您已同步所有手动访问地图的操作,因此您不需要包装器。

对于您的问题,是否要使用 Collections.synchronizedSortedMap 。在第二次访问中,您将某些东西放到了地图上,您不必手动同步,因为puts方法已经由syncedSortedMap包装器同步。您已在 getNextAvailableExecutionOrder 方法中正确同步了对地图的访问,因为确实流对地图进行了迭代,并且您需要手动进行同步,如javadoc中所述。