获取地图线程安全性的更新值

时间:2016-12-27 13:34:05

标签: java multithreading hashmap

我在第4.3册中读到。在实践中的并发中委托线程安全使用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

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

2 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

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

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();



    }

}

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