java - 下面这段代码存在并发陷阱???
PHP中文网
PHP中文网 2017-04-18 10:10:31
0
2
464

曾宪杰的《大型网站系统与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中文网

认证高级PHP讲师

membalas semua(2)
巴扎黑

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.

左手右手慢动作

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.

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!