Java ConcurrentHashMap是如何实现线程安全的

Java 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需要锁来读取开放,尽管它不影响对象。
  • 在HashMap中,如果一个线程正在迭代一个对象,另一个线程正试图访问同一个对象,它会抛出ConcurrentModificationException,而concurrent hashmap不会抛出ConcurrentModificationException。

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

  • java.util.Concurrent.ConcurrentHashMap类通过将地图分成若干段来实现线程安全,锁不是针对整个对象而是针对一个段,即一个线程需要一个段的锁。
  • 在ConcurrentHashap中,读操作不需要任何锁。

示例 1:

// Java Program to llustarte ConcurrentModificationException
// Using Normal Collections
 
// Importing required classes
import java.util.*;
import java.util.concurrent.*;
 
// Main class extending Thread class
class GFG extends Thread {
 
    // Creating a static HashMap class object
    static HashMap m = new HashMap();
 
    // run() method for the thread
    public void run()
    {
 
        // Try block to check for exceptions
        try {
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(2000);
        }
 
        // Catch block to handle exceptions
        catch (InterruptedException e) {
        }
 
        // Display message
        System.out.println("Child Thread updating Map");
 
        // Putting element in map
        m.put(103, "C");
    }
 
    // Method 2
    // Main driver method
    public static void main(String arg[])
        throws InterruptedException
    {
 
        // Adding elements to map object created above
        // using put() method
        m.put(101, "A");
        m.put(102, "B");
 
        // Creating thread inside main() method
        GFG t = new GFG();
 
        // Starting the thread
        t.start();
 
        // Operating keySet() method and
        // storing it in Set class object
        Set s1 = m.keySet();
 
        // Iterating over Set class object
        // using iterators
        Iterator itr = s1.iterator();
 
        // Holds true till there is single element present
        // inside object
        while (itr.hasNext()) {
 
            // traversing over elements in object
            // using next() method
            Integer I1 = (Integer)itr.next();
 
            // Print statement
            System.out.println(
                "Main Thread Iterating Map and Current Entry is:"
                + I1 + "..." + m.get(I1));
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(3000);
        }
 
        // Printing all elements on console
        System.out.println(m);
    }
}

输出:

Main Thread Iterating Map and Current Entry is:101...A
Child Thread updating Map
Exception in thread "main" java.util.ConcurrentModificationException
       at java.base/java.util.HashMapHashIterator.nextNode(HashMap.java:1493)
       at java.base/java.util.HashMapKeyIterator.next(HashMap.java:1516)
       at Main.main(Main.java:30)

输出解释。

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

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

示例 2:

// Java Program to llustarte ConcurrentModificationException
// Using ConcurrentHashMap
 
// Importing required classes
import java.util.*;
import java.util.concurrent.*;
 
// Main class extending Thread class
class Main extends Thread {
 
    // Creating static concurrentHashMap object
    static ConcurrentHashMap<Integer, String> m
        = new ConcurrentHashMap<Integer, String>();
 
    // Method 1
    // run() method for the thread
    public void run()
    {
 
        // Try block to check for exceptions
        try {
 
            // Making thread to sleep for 2 seconds
            Thread.sleep(2000);
        }
 
        // Catch block to handle the exceptions
        catch (InterruptedException e) {
        }
 
        // Display message
        System.out.println("Child Thread updating Map");
 
        // Inserting element
        m.put(103, "C");
    }
 
    // Method 2
    // Main driver method
    public static void main(String arg[])
        throws InterruptedException
    {
 
        // Adding elements to object created of Map
        m.put(101, "A");
        m.put(102, "B");
 
        // Creating thread inside main() method
        Main t = new Main();
 
        // Starting thread
        t.start();
 
        // Creating object of Set class
        Set<Integer> s1 = m.keySet();
 
        // Creating iterator for traversal
        Iterator<Integer> itr = s1.iterator();
 
        // Condition holds true till there is single element
        // in Set object
        while (itr.hasNext()) {
 
            // Iterating over elements
            // using next() method
            Integer I1 = itr.next();
 
            // Display message
            System.out.println(
                "Main Thread Iterating Map and Current Entry is:"
                + I1 + "..." + m.get(I1));
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(3000);
        }
 
        // Display elements of map objects
        System.out.println(m);
    }
}

输出

Main Thread Iterating Map and Current Entry is:101...A
Child Thread updating Map
Main Thread Iterating Map and Current Entry is:102...B
Main Thread Iterating Map and Current Entry is:103...C
{101=A, 102=B, 103=C}

输出解释。

上述程序中使用的类扩展了线程类。让我们看看控制流,我们知道在ConcurrentHashMap中,当一个线程在迭代时,其余的线程被允许以安全的方式执行任何修改。在上面的程序中,主线程正在更新Map,与此同时,子线程也在试图更新Map对象。这个程序不会抛出ConcurrentModificationException。

Hashtable, Hashmap, ConcurrentHashmap之间的区别

HashTable HashMap ConcurrentHashmap
我们将通过锁定整个地图对象来获得线程安全。 它不是线程安全的。 我们将获得线程安全,而不需要锁定整个地图对象,只需使用段级锁。
每个读和写操作都需要一个objectstotal map对象锁。 它不需要锁。 读取操作可以在没有锁的情况下进行,但写入操作可以在段级锁的情况下进行。
每次只允许一个线程对地图进行操作(同步)。 在一个时间段内,不允许多个线程操作。它将抛出一个异常 在同一时间,允许多个线程以安全的方式对地图对象进行操作
当一个线程迭代地图对象时,其他线程不允许修改地图,否则我们会得到 ConcurrentModificationException。 当一个线程迭代地图对象时,其他线程不允许修改地图,否则我们会得到 ConcurrentModificationException。 当一个线程迭代地图对象时,其他线程可以修改地图,我们就不会得到ConcurrentModificationException。
键和值都不允许为空 HashMap允许一个空键和多个空值 键和值都不允许为空。
在1.0版本中引入 在1.2版本中引入 在1.5版本中引入

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程