Rumah  >  Soal Jawab  >  teks badan

java - 下面这段代码存在并发陷阱???

曾宪杰的《大型网站系统与Java中间件实践》第一章第1.2.2.3小节给出以下代码示例:

使用HashMap数据被进行统计;

public class TestClass
{
    private HashMap<String, Integer> map = new HashMap<>();
    
    public synchronized void add(String key)
    {
        Integer value = map.get(key);
        if(value == null)
        {
            map.put(key, 1);
        }
        else
        {
            map.put(key, value + 1);
        }
    } 
}

使用ConcurrentHashMap保存数据并进行统计;

public class TestClass
{
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
    
    public void add(String key)
    {
        Integer value = map.get(key);
        if(value == null)
        {
            map.put(key, 1);
        }
        else
        {
            map.put(key, value + 1);
        }
    } 
}

使用HashMap时,对add方法加锁,此时该方法是线程安全的,为何换为ConcurrentHashMap之后,原书中说存在并发陷阱???

PHP中文网PHP中文网2717 hari yang lalu485

membalas semua(2)saya akan balas

  • 巴扎黑

    巴扎黑2017-04-18 10:12:31

    Mengapa kita perlu mengunci kaedah tambah selepas menukar kepada ConcurrentHashMap? ? ?

    public void add(String key)
        {
            Integer value = map.get(key);
            if(value == null)
            {
                map.put(key, 1);
            }
            else
            {
                map.put(key, value + 1);
            }
        } 

    Ia tidak berkunci.

    EDIT:

    Memang ada perangkap konkurensi. Pertimbangkan situasi ini:

    1. Thread A melaksanakan map.get(key);if(value == null) untuk mendapatkan hasil yang benar, dan kemudian menyerahkan masa CPU.

    2. Pada masa ini, utas B juga dilaksanakan ke tempat yang sama, dan hasilnya juga benar, kerana utas A belum lagi melaksanakan map.put(kunci, 1), dan utas B telah melaksanakan map.put (kunci, 1) , Pada masa ini, peta sudah mempunyai nilai kunci.

    3. Thread A mendapat masa CPU untuk meneruskan pelaksanaan Kerana keputusan penghakiman sebelumnya adalah benar, thread A diletakkan semula. Hasil akhir ialah kedua-dua utas melaksanakan map.put(key, 1) sekali Pada masa ini, nilai kunci masih 1, tetapi ia sepatutnya 2.

    Sebab masalah ini wujud ialah satu operasi ConcurrentHashMap adalah atom, tetapi panggilan luaran anda bukan atomic map.get dan map.put adalah dua operasi, bebas antara satu sama lain, jadi jika anda mahu Untuk memastikan urutan keselamatan, anda masih perlu menambah kunci pada kod anda untuk memastikan keatomisan operasi dapatkan dan letak.

    balas
    0
  • ringa_lee

    ringa_lee2017-04-18 10:12:31

    ConcurrentHashMap hanya menjamin bahawa data dalamannya boleh kekal konsisten di bawah keadaan serentak, yang tidak boleh dilakukan oleh HashMap.

    Tetapi kaedah tambah tidak selamat untuk benang kerana ia adalah Semak-Kemudian-Bertindak atau Baca-Ubahsuai-Tulis.

    Anda boleh fikirkan tentang soalan ini, jika semua medan dalam kelas adalah kelas selamat untuk benang, maka sama ada kelas ini selamat untuk benang. Jawapannya jelas tidak.

    balas
    0
  • Batalbalas