多个线程访问非同步映射

时间:2014-08-27 17:51:31

标签: java multithreading synchronization synchronized

我正面临这个问题,我有两个A和B类,'A类'有两个主题t1和t2,它试图访问'B类'地图,如下所示问题是,我不能做任何修改因为我不能使用synchronised关键字,或者我不能将它放在同步方法中。所以我的疑问是,还有其他方法来同步这张地图。

public class A{

    static B b = new B();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {

                Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
                map.put(1, "one");
                map.put(2, "two");
                map.put(3, "three");
                b.setMap(map);
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {

                Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
                map.put(4, "four");
                map.put(5, "five");
                map.put(6, "six");
                b.setMap(map);

            }
        });

        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        for(Map.Entry<Integer, String> entry : b.getMap().entrySet()){
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }     
    }

我正在使用LinkedHashMap,仅用于跟踪插入顺序(忽略性能问题)

public class B{

    private Map<Integer,String> map = new LinkedHashMap<Integer,String>();

    public Map<Integer,String> getMap() {
        return map;
    }

    public void setMap(Map<Integer,String> map) {
        this.map = map;
    }
} 

4 个答案:

答案 0 :(得分:2)

您可以创建一次同步Map并让两个线程都使用该Map个实例。

final Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
b.setMap(map);

Thread t1 = new Thread(new Runnable() {

    @Override
    public void run() {
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
    }
});

Thread t2 = new Thread(new Runnable() {
    @Override
    public void run() {
        map.put(4, "four");
        map.put(5, "five");
        map.put(6, "six");
    }
});

答案 1 :(得分:1)

为什么不在B中设置地图。如果您无法使用ConcurrentHashMap,则可以使用Collections.synchronizedMap(new LinkedHashMap<>())代替。任何外部同步都将始终存在对映射进行不同步访问的可能性。


public class A{

    static B b;
    static {
        b = new B();
        b.setMap(new ConcurrentHashMap());
    }
    //...
}

答案 2 :(得分:1)

正如其他人指出的那样,您可以使用同步包装器,而java.util.Collections提供了一种方便的方法来获取一个。但是,让每个线程获得自己的同步包装对你没有帮助 - 所有参与者都需要使用相同的同步工具。

更一般地说,如果您需要同步访问一些不太方便的对象,那么您可以使用外部同步。在您的情况下,可能如下所示:

public class A{

    static B b = new B();
    // will use this object to synchronize access to b's map:
    static Object bLock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Map<Integer,String> map = b.getMap();

                synchronized(bLock) {
                    map.put(1, "one");
                    map.put(2, "two");
                    map.put(3, "three");
                }
                // no need for setMap()
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Map<Integer,String> map = b.getMap();

                synchronized (bLock) {
                    map.put(4, "four");
                    map.put(5, "five");
                    map.put(6, "six");
                }
                // no need for setMap()
            }
        });

        // ...
    }
}

包java.util.concurrent.locks也有一些你可以使用的锁类,但通常你不需要任何这么花哨的东西。

答案 3 :(得分:0)

简单地:

public class A{

    static B b;
    static Map bMap;

    static {
        b = new B();
        bMap = Collections.synchronizedMap(b.getMap());
    }

    ... //now use bMap instead
}