ConcurrentHashMap同时读取和更新

您所在的位置:网站首页 多线程处理同一个对象 ConcurrentHashMap同时读取和更新

ConcurrentHashMap同时读取和更新

2023-08-22 18:26| 来源: 网络整理| 查看: 265

 

1. HashMap:

如果2个不同的线程同时对同一个HashMap对象执行操作,则编译器将引发ConcurrentModificationException

我们将演示一个使用HashMap的简单示例,该示例执行

1个第一螺纹迭代或读取的条目一个接一个2第二螺纹去除键-值对; 而其他线程正在迭代HashMap对象

IterateAndModifyHashMapSimultaneously.java

? 1个 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18岁 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 package in.bench.resources.concurrent.collection;   import java.util.HashMap; import java.util.Map;   // extending Thread class public class IterateAndModifyHashMap extends Thread {       // creating HashMap object of type     static HashMap hm =             new HashMap();       @Override     public void run() {           try {             // sleeping thread for 1000 ms             Thread.sleep(1000);               // removing entry with key=1             String value = hm.remove(1);             System.out.println("Entry with {key=1" +                     " & value=" + value + "} is removed");         }         catch(InterruptedException iex) {             iex.printStackTrace();         }         System.out.println("Removal is done... !!");     }       /**      * main() method      * @param args      * @throws InterruptedException      */     public static void main(String[] args) throws InterruptedException {           // adding key-value pairs to HashMap object         hm.put(1, "google.com");         hm.put(2, "youtube.com");         hm.put(3, "facebook.com");           // creating another thread         Thread newThread = new Thread(new IterateAndModifyHashMap());         newThread.start();           // iterating HM object using enhanced for-loop         for(Map.Entry me : hm.entrySet()) {               System.out.println("{Key=" + me.getKey()                     + "\t" + "Value=" + me.getValue() + "}");               // sleeping thread for 1500 ms, after every turn             Thread.sleep(1500);         }         System.out.println("Iterating completed... !!");     } }

输出:

? 1个 2 3 4 5 6 7 8 9 {Key=1  Value=google.com} Entry with {key=1 & value=google.com} is removed Removal is done... !! Exception in thread "main" java.util.ConcurrentModificationException     at java.util.HashMap$HashIterator.nextEntry(HashMap.java:895)     at java.util.HashMap$EntryIterator.next(HashMap.java:935)     at java.util.HashMap$EntryIterator.next(HashMap.java:933)     at in.bench.resources.concurrent.collection         .IterateAndModifyHashMap.main(IterateAndModifyHashMap.java:48)

说明:

主线程迭代HashMap对象,子线程使用key = 1删除HashMap条目从输出中可以清楚地看到,当一个线程在HashMap对象上进行迭代,并且是否有其他线程执行修改操作时(即,在同一HashMap对象上,另一个线程正在删除条目)然后编译器将抛出ConcurrentModificationException注意:介绍学习示例的sleep(ms)因为没有睡眠,两个线程都将独立执行(在nano / pico秒内完成其执行),并且不会出现任何编译时错误由于我们试图用少量的数据来理解(执行在十亿分之一秒内完成)但是,由于有大量数据,不需要引入睡眠概念随着每个线程执行时间的增加,肯定会引发ConcurrentModificationException

 

问)如何克服上述HashMap异常?

随着ConcurrentHashMap中,我们可以克服这个问题因为它适用于不同的锁定策略 或不同的并发级别

 

2. ConcurrentHashMap:

当2个不同的线程同时对同一个ConcurrentHashMap对象执行操作时,编译器将不会引发任何运行时异常

这是使用ConcurrentHashMap而不是HashMap的优点

在演示示例中,

  1日线程迭代通过的ConcurrentHashMap的所有键值对虽然其他线程可以安全地删除key = 1的键/值对与HashMap不同,编译器不会引发任何ConcurrentModificationException这是因为ConcurrentHashMap在不同的并发级别或不同的锁定策略下工作

IterateAndModifyConcurrentHashMapSimultaneously.java

? 1个 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18岁 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 package in.bench.resources.concurrent.collection;   import java.util.Map; import java.util.concurrent.ConcurrentHashMap;   // implementing Runnable interface public class IterateAndModifyConcurrentHashMap implements Runnable {       // creating ConcurrentHashMap object of type     static ConcurrentHashMap chm =             new ConcurrentHashMap();       @Override     public void run() {           try {             // sleeping thread for 1000 ms             Thread.sleep(1000);               // removing entry with key=1             String value = chm.remove(1);             System.out.println("Entry with {key=1"                     + " & value=" + value + "} is removed");         }         catch(InterruptedException iex) {             iex.printStackTrace();         }         System.out.println("Removal is done... !!");     }       /**      * main() method      * @param args      * @throws InterruptedException      */     public static void main(String[] args) throws InterruptedException {           // adding key-value pairs to ConcurrentHashMap object         chm.put(1, "google.com");         chm.put(2, "youtube.com");         chm.put(3, "facebook.com");           // creating another thread         Thread newThread = new Thread(                 new IterateAndModifyConcurrentHashMap());         newThread.start();           // iterating CHM object using enhanced for-loop         for(Map.Entry me : chm.entrySet()) {               System.out.println("{Key=" + me.getKey()                     + "\t" + "Value=" + me.getValue() + "}");               // sleeping thread for 2000 ms, after every turn             Thread.sleep(2000);         }         System.out.println("Iterating completed... !!");     } }

输出:

? 1个 2 3 4 5 {Key=3  Value=facebook.com} Entry with {key=1 & value=google.com} is removed Removal is done... !! {Key=2  Value=youtube.com} Iterating completed... !!

说明:

当我们执行相同的程序用ConcurrentHashMap替换HashMap时,程序执行时没有任何运行时异常,例如ConcurrentModificationException但是在不同的执行点可能会有不同的输出原因:因为,当一个线程迭代 所有条目时, 它可能会 从第二个线程获得 更新的条目在上面的例子中,我们得到了更新的条目,这是可能的,因为1个第一螺纹,其是迭代得到更新用从2次螺纹(去除)下一次迭代也是如此,因为下一次可能会迭代所有条目(在这种情况下,第一个不会从第二个线程进行更新)

 

让我们也打印其他可能性

输出:

? 1个 2 3 4 5 6 {Key=1  Value=google.com} Entry with {key=1 & value=google.com} is removed Removal is done... !! {Key=2  Value=youtube.com} {Key=3  Value=facebook.com} Iterating completed... !!

从上面的输出,很显然,1个第一线程没有得到更新用来自2次螺纹和1条第一线穿过的所有条目迭代



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3