Java中ConcurrentHashMap是如何实现线程安全
目录
- 语法:
- ConcurrentHashmap 的需要:
- 如何使 ConcurrentHashMap 线程安全成为可能?
- Hashtable、Hashmap、ConcurrentHashmap的区别
ConcurrentHashMap是一个哈希表,支持检索的全并发和更新的高预期并发。此类遵循与 Hashtable 相同的功能规范,并包含 Hashtable 的所有方法。ConcurrentHashMap 位于 java.util.Concurrent 包中。
语法:
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
到此这篇关于Java中ConcurrentHashMap是如何实现线程安全的文章就介绍到这了,更多相关Java ConcurrentHashMap线程安全内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!