Java中ConcurrentHashMap是怎么实现线程安全的

这篇文章主要介绍“Java中ConcurrentHashMap是怎么实现线程安全的”,在日常操作中,相信很多人在Java中ConcurrentHashMap是怎么实现线程安全的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中ConcurrentHashMap是怎么实现线程安全的”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

语法:

public class ConcurrentHashMap<K,V>
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable

其中 K 指的是这个映射所维护的键的类型,V 指的是映射值的类型

ConcurrentHashmap 的需要:

  • HashMap虽然有很多优点,但不能用于多线程,因为它不是线程安全的。

  • 尽管 Hashtable 被认为是线程安全的,但它也有一些缺点。例如,Hashtable 需要锁定才能读取打开,即使它不影响对象。

  • n HashMap,如果一个线程正在迭代一个对象,另一个线程试图访问同一个对象,它会抛出 ConcurrentModificationException,而并发 hashmap 不会抛出 ConcurrentModificationException。

如何使 ConcurrentHashMap 线程安全成为可能?

  • java.util.Concurrent.ConcurrentHashMap类通过将map划分为segment来实现线程安全,不是整个对象需要锁,而是一个segment,即一个线程需要一个segment的锁。

  • 在 ConcurrenHashap 中,读操作不需要任何锁。

示例 1:

import java.util.*;
import java.util.concurrent.*;

// 扩展Thread类的主类
class GFG extends Thread {

 // 创建静态 HashMap 类对象
 static HashMap m = new HashMap();

 public void run()
 {

  // try 块检查异常
  try {

   // 让线程休眠 3 秒
   Thread.sleep(2000);
  }
  catch (InterruptedException e) {
  }
  System.out.println("子线程更新映射");
  m.put(103, "C");
 }
 public static void main(String arg[])
  throws InterruptedException
 {
  m.put(101, "A");
  m.put(102, "B");
  GFG t = new GFG();
  t.start();
  Set s1 = m.keySet();
  Iterator itr = s1.iterator();
  while (itr.hasNext()) {
   Integer I1 = (Integer)itr.next();
   System.out.println(
    "主线程迭代映射和当前条目是:"
    + I1 + "..." + m.get(I1));
   Thread.sleep(3000);
  }
  System.out.println(m);
 }
}

输出:
主线程迭代映射和当前条目是:101…A
子线程更新映射
Exception in thread "main" java.util.ConcurrentModificationException
       at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
       at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
       at Main.main(Main.java:30)

输出说明:

上述程序中使用的类扩展了 Thread 类。让我们看看控制流。所以,最初,上面的java程序包含一个线程。当我们遇到语句 Main t= new Main() 时,我们正在为扩展 Thread 类的类创建一个对象。因此,每当我们调用 t.start() 方法时,子线程都会被激活并调用 run() 方法. 现在主线程开始执行,每当子线程更新同一个地图对象时,都会抛出一个名为 ConcurrentModificationException 的异常。    

现在让我们使用 ConcurrentHashMap 来修改上面的程序,以解决上述程序在执行时产生的异常。

示例 2:

import java.util.*;
import java.util.concurrent.*;

class Main extends Thread {
 static ConcurrentHashMap<Integer, String> m
  = new ConcurrentHashMap<Integer, String>();
 public void run()
 {
  try {
   Thread.sleep(2000);
  }
  catch (InterruptedException e) {
  }
  System.out.println("子线程更新映射");
  m.put(103, "C");
 }
 public static void main(String arg[])
  throws InterruptedException
 {
  m.put(101, "A");
  m.put(102, "B");
  Main t = new Main();
  t.start();
  Set<Integer> s1 = m.keySet();
  Iterator<Integer> itr = s1.iterator();
  while (itr.hasNext()) {
   Integer I1 = itr.next();
   System.out.println(
    "主线程迭代映射和当前条目是:"
    + I1 + "..." + m.get(I1));
   Thread.sleep(3000);
  }
  System.out.println(m);
 }
}

输出

主线程迭代映射和当前条目是:101…A
子线程更新映射
主线程迭代映射和当前条目是:102…B
主线程迭代映射和当前条目是:103…C
{101=A, 102=B, 103=C}

输出说明:
上述程序中使用的 Class 扩展了Thread 类。让我们看看控制流,所以我们知道在 ConcurrentHashMap 中,当一个线程正在迭代时,剩余的线程可以以安全的方式执行任何修改。上述程序中主线程正在更新Map,同时子线程也在尝试更新Map对象。本程序不会抛出 ConcurrentModificationException。

Hashtable、Hashmap、ConcurrentHashmap的区别

Hashtable Hashmap ConcurrentHashmap
我们将通过锁定整个地图对象来获得线程安全。 它不是线程安全的。 我们将获得线程安全,而无需使用段级锁锁定 Total Map 对象。
每个读写操作都需要一个objectstotal 映射对象锁。 它不需要锁。 读操作可以不加锁执行,写操作可以用段级锁执行。
一次只允许一个线程在地图上操作(同步) 不允许同时运行多个线程。它会抛出异常 一次允许多个线程以安全的方式操作地图对象
当一个线程迭代 Map 对象时,其他线程不允许修改映射,否则我们会得到 ConcurrentModificationException 当一个线程迭代 Map 对象时,其他线程不允许修改映射,否则我们会得到 ConcurrentModificationException 当一个线程迭代 Map 对象时,其他线程被允许修改地图,我们不会得到 ConcurrentModificationException
键和值都不允许为 Null HashMap 允许一个空键和多个空值 键和值都不允许为 Null。
在 1.0 版本中引入 在 1.2 版本中引入 在 1.5 版本中引入

到此,关于“Java中ConcurrentHashMap是怎么实现线程安全的”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

原创文章,作者:3628473679,如若转载,请注明出处:https://blog.ytso.com/tech/dev/209068.html

(0)
上一篇 2021年12月7日 17:30
下一篇 2021年12月7日 17:30

相关推荐

发表回复

登录后才能评论