【问题标题】:Get update value in map thread safety在地图线程安全中获取更新值
【发布时间】:2016-12-27 22:28:01
【问题描述】:

我在书 4.3 中读到过。在 Concurrency in Practice 中委派线程安全 使用 final 和 Collections.unmodifiableMap(map) How does DelegatingVehicleTracker (p. 65 Goetz) return a "live" view? 委派线程安全,我尝试创建我的示例并看到一个线程所做的更改没有得到反映返回地图时。我做错了什么

public class MapDem {

final Map<Integer, Integer> map;

final Map<Integer, Integer> map1;

public MapDem() {
    map = new HashMap<Integer, Integer>();
    map.put(1, 10);
    map.put(2, 20);
    map1 = Collections.unmodifiableMap(map);
}

public Map<Integer, Integer> getMap() {
    return Collections.unmodifiableMap(new HashMap<Integer, Integer>(map));
}

public void setValue(int key,int value){
    map.replace(key, value);
}


public static void main(String args[]) {
    MapDem demo = new MapDem();

    Thread t3 = new Thread(new Runnable() {

        @Override
        public void run() {
            System.out.println(demo.getMap());

        }

    });
    t3.start();

    Thread t4 = new Thread(new Runnable() {

        @Override
        public void run() {
            demo.setValue(2, 40);

        }

    });
    t4.start();

    try {
        t3.join();
        t4.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println(demo.getMap().size());

   }

 }

输出是

{1=10, 2=20}
 2
 or 
{1=10, 2=40}
 2

我希望地图始终看到更新后的值。

【问题讨论】:

  • 请在此处填写您的期望和结果,以便更好地理解您的问题
  • 更新了请查收
  • concurentMap 是你想要的吗?
  • 我想在没有并发地图的情况下达到同样的效果,请参阅我在问题中提到的链接

标签: java multithreading hashmap


【解决方案1】:

抱歉,我在之前的回答中误读了您的代码。

要返回“实时”视图,您必须与其他线程共享底层映射(毕竟这是“实时”的定义。您希望看到其他线程完成的更新)。您对此共享映射使用什么实现(无论是同步的还是 ConcurrentHashMap)是无关紧要的。 unmodifiable 的包装与并发无关 - 它只是使地图成为“视图”,即只读。

所有这些都不会使t3t4 之前执行。为此,您需要在它们之间引入发生前的关系。最简单的方法是先加入t4,然后启动t3

【讨论】:

  • 我理解,但我无法接受这种加入的真实场景。我想要一个解决方案,以便地图始终读取更新的值
  • 你需要考虑这一点,以防线程 1 总是读取 map 的实际值。它不会等待更新的值,除非您将实施某种会知道旧值然后仅在更改后读取的阻止程序。在这个例子中,线程 1 是否会在线程 2 之前执行是不确定的
  • stackoverflow.com/questions/33532745/… 参考链接我指的是这个场景
【解决方案2】:

我想你不太明白它是关于什么的。或者也许是我,但我会试着告诉你我在想什么。这不是等待更新的值,而是只允许在一个对象中进行更改,而可以从其他对象中读取。看看我的代码:

public class DelegatingVehicleTracker {
    private final ConcurrentMap<String, String> locations;
    private final Map<String, String> unmodifiableMap;

    public DelegatingVehicleTracker(Map<String, String> points) {
        locations = new ConcurrentHashMap<String, String>(points);
        unmodifiableMap = Collections.unmodifiableMap(locations);
    }

    public Map<String, String> getLocations() {
        return unmodifiableMap;
    }

    public String getLocation(String id) {
        return locations.get(id);
    }

    public void setLocation(String id, int x, int y) {
        if (locations.replace(id, x + y + "") == null)
            throw new IllegalArgumentException("invalid vehicle name: " + id);
    }

    public static void main(String[] args) {

        HashMap<String, String > vehicles= new HashMap<>();

        vehicles.put("1", "1");

        DelegatingVehicleTracker tracker = new DelegatingVehicleTracker(vehicles);

        Map<String, String> unmodifiableMap = tracker.getLocations();


        new Thread(() -> {
            while(true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(unmodifiableMap);
            }
        }).start();

        new Thread(() -> {
            int i=0;
            while(true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                tracker.setLocation("1",i+1, i+2);
                i++;
            }
        }).start();



    }

}

在主要方法中,我从对象跟踪器获取不可修改的地图,我的一个线程正在使用它来显示此地图中的值。它将始终显示当前值,因此如果它在其他线程执行 set Location 之前执行“sout”,则值将是“旧”值,但您需要看到这不是“旧”值,它是当前值在执行“sout”时正在收集。正如我在评论中所说,如果您想查看更新的值,则需要等待更新,这是另一种情况。这里的线程安全是您可以将收藏扔给所有人,但他们只有读取此地图的权限,因此您无法直接访问收藏。只能通过 DelegatingVehicleTracker 执行 setLocation。

【讨论】:

    猜你喜欢
    • 2013-04-29
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多