Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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 我的代码是线程安全的吗?如果没有,如何在这种情况下实现线程安全?_Java_Multithreading_Arraylist_Collections_Thread Safety - Fatal编程技术网

Java 我的代码是线程安全的吗?如果没有,如何在这种情况下实现线程安全?

Java 我的代码是线程安全的吗?如果没有,如何在这种情况下实现线程安全?,java,multithreading,arraylist,collections,thread-safety,Java,Multithreading,Arraylist,Collections,Thread Safety,我在面试中被问到一个问题。。 如果我想像这样在地图中存储值,该怎么办: key_1 --> value 1 key_2 --> value 2 key_1 --> value 3 这里,如果我们假设键和值都在字符串中,那么我们应该像这样获取映射 Map<String,List<String>> m1 = new HashMap(); 这里,假设线程t1和t2并行运行。所以,如果列表中的我的意思是ConcurrentHashMap中的值是线程安全的吗?

我在面试中被问到一个问题。。 如果我想像这样在地图中存储值,该怎么办:

key_1 --> value 1
key_2 --> value 2
key_1 --> value 3
这里,如果我们假设键和值都在字符串中,那么我们应该像这样获取映射

Map<String,List<String>> m1 = new HashMap();

这里,假设线程t1和t2并行运行。所以,如果
列表中的
我的意思是ConcurrentHashMap中的值是线程安全的吗?如果是,那怎么办?如果没有,那么如何实现这一点呢???ConcurrentHashMap是线程安全的数据结构。如果在
ConcurrentHashMap
的值中使用
List
(它不是线程安全的),则
List
不是线程安全的,因为两个线程可以保护List的引用,然后并行修改它


ConcurrentHashMap
是线程安全的,这意味着它的操作,如
put
putAll
e.t.c是线程安全的。这并不意味着你使用的数据结构作为它的值也成为线程安全的

如何做到这一点?

  • 使用线程安全的
    List
    CopyOnWriteArrayList
    一样作为
    ConcurrentHashMap
    中的值
  • 使自定义
    列表
    并使其所有方法
    同步
  • 通过传入集合,将非线程安全的
    列表
    转换为线程安全的
    列表
    。synchronizedList(非线程安全列表)
我说我们可以用ConcurrentHashMap来实现这个目的他们说可以

也许没关系,也许没关系。这取决于键1和键2之间是否存在特殊关系

假设一个线程为key_1存储一个新值,然后就在它可以为key_2存储一个相关值之前,它的时间片结束了。然后,另一个线程在第一个线程挂起时检查键1和键2的值。它看到键_1的新值,但看到键_2的旧值

在这一点上,第一个线程只更新了两个键的一半有关系吗


插入
ConcurrentHashMap
将确保map数据结构本身在多线程应用程序中不会做任何有趣或错误的事情,但如果应用程序依赖于始终同时更新的这两个键,然后,您仍然需要某种显式锁定,以确保它们始终一起更新。

通过代码进行测试很容易:

        Map<String,List<String>> m1 = new ConcurrentHashMap();
        m1.put("s1", new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            int i = 500;
            while (i-- > 0) {
                m1.get("s1").add(i + "");
            }
            countDownLatch.countDown();
        }).start();

        new Thread(() -> {
            int i = 500;
            while (i-- > 0) {
                m1.get("s1").add(i + "");
            }
            countDownLatch.countDown();
        }).start();
        countDownLatch.await();
        // may be < 1000,
        // or ArrayIndexOutOfBoundsException happens before this line of code executes
        System.out.println(m1.get("s1").size()); 
Map m1=新的ConcurrentHashMap();
m1.put(“s1”,新的ArrayList());
CountDownLatch CountDownLatch=新的CountDownLatch(2);
新线程(()->{
int i=500;
而(i-->0){
m1.获取(“s1”).添加(i+);
}
countdownlock.countDown();
}).start();
新线程(()->{
int i=500;
而(i-->0){
m1.获取(“s1”).添加(i+);
}
countdownlock.countDown();
}).start();
倒计时闩锁。等待();
//可能小于1000,
//或ArrayIndexOutOfBoundsException在这行代码执行之前发生
System.out.println(m1.get(“s1”).size());

这取决于列表的实现。存储在ConcurrentHashMap中的值的线程安全性不高于或低于映射之外的值。@AndyTurner,请详细解释一下好吗?我没有理解你。对此很抱歉。你在地图上执行的操作将是线程安全的,即get()和put()以及containsKey()。但是,一旦获取了值[在您的示例中是一个列表],与特定列表元素相关的修改的线程安全性将完全取决于列表对象[或任何其他java对象]的实现。
        Map<String,List<String>> m1 = new ConcurrentHashMap();
        m1.put("s1", new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            int i = 500;
            while (i-- > 0) {
                m1.get("s1").add(i + "");
            }
            countDownLatch.countDown();
        }).start();

        new Thread(() -> {
            int i = 500;
            while (i-- > 0) {
                m1.get("s1").add(i + "");
            }
            countDownLatch.countDown();
        }).start();
        countDownLatch.await();
        // may be < 1000,
        // or ArrayIndexOutOfBoundsException happens before this line of code executes
        System.out.println(m1.get("s1").size());