`
rainshow
  • 浏览: 31433 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
文章分类
社区版块
存档分类
最新评论

ConcurrentHashMap死锁的疑惑

阅读更多
最近在使用ConcurrentHashMap的过程中,发现ConcurrentHashMap在一定的条件下会导致死锁(这个条件目前还不知道到底什么,我的ConcurrentHashMap多个线程共享,会删除和增加一些数据到ConcurrentHashMap对象里)

具体的现象是:程序跑了一段时间(10几个小时),一般2个线程会同时停下来,这时CPU占用20%左右(服务器是多CPU的),再隔一段时间又有两个线程同时停下来,这时CPU占用50%左右,这种情况一直延续知道CPU100%

起先以为程序中出现了死循环导致CPU100%,后来加了调试发现上面的现象并把其中的ConcurrentHashMap换成传统的synchronized HashMap后问题就解决了。

这个问题很奇怪,虽然现在解决了,还是不明白什么情况下会导致ConcurrentHashMap死锁呢?
分享到:
评论
9 楼 srdrm 2009-02-26  
我倒,putAll可不是太好的操作。你的设计完全是有问题的。
8 楼 puroc 2008-12-14  
1.多线程使用HashMap,有死循环的问题,我遇到过两次了。
2.我现在用的也是ConcurrentHashMap,并发量很大,没遇到什么问题。
7 楼 rainshow 2008-09-24  
nihongye 写道
cpu占用那么多,说明是死循环,比如HashMap在多线程下,get操作有可能陷入死循环,注意这种要求同步的访问。

这个说法可靠吗?我看了一下HashMap的get方法源码

for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next)


如果在e.next=e的情况下似乎会进入死循环。

你说的这个情况还是很有可能的,这个程序写的很早了,写的人也比较多,从代码里看同一个HashMap的引用是很有可能被派发到多个线程里去的。
6 楼 nihongye 2008-09-24  
cpu占用那么多,说明是死循环,比如HashMap在多线程下,get操作有可能陷入死循环,注意这种要求同步的访问。
5 楼 bloodrate 2008-09-23  
ConcurrentHashMap用的是似有锁,用户拿不到锁对象,怎么会死锁阿
4 楼 rainshow 2008-09-23  
更正一下,并且说详细一点(附件中是对象关系图)

我们的一个系统,以下简称V系统

1)V系统包含2、3个Producer线程他们往队列里放入一个Map对象(HashMap)。但是这套程序存在一些问题,不排除不同的Map对象里还有对相同的对象的引用,也就是说map1和map2可能都引用了someObj,也有可能引用了一些共享数据

2)V系统同时包含50-100个Consumer线程,他们从队列里取出Map对象map3,并在取出后建立自己的对象map4,并把map3中的引用putAll到map4中

3)这些Producer线程和Consumer线程共享了一些配置数据(这些数据都是存放在ConcurrentHashMap中)

问题出现在把map3中的引用putAll到map4中的时候引起了死锁
关于程序设计的问题我们这里不讨论,这里会导致死锁的有两个地方,Queue和ConcurrentHashMap,但他们本身也不会死锁,我比较疑惑的是究竟在什么情形下会导致程序死锁。再次强调一下,在这里除了Queue和共享数据外,其他的map都是HashMap,putAll时的死锁有点匪夷所思。

当然大家也不要被我的想法给限制了,也有可能不是死锁,反正现象就是2个线程停在putAll哪里不动了,狂吃CPU

Queue这个类的源代码如下:

public class Queue {
    private final int maxSize;//如果超过最大值则删除

    private volatile LinkedList<Object> queue = new LinkedList<Object>();
    private Lock lock;
    private Condition notEmpty;

    public Queue(int maxSize) {
        this.maxSize = maxSize > 0 ? maxSize : Integer.MAX_VALUE;
        lock = new ReentrantLock();
        notEmpty = lock.newCondition();
    }

    public void put(Object v) {
        lock.lock();
        try {
            int s = queue.size();
            if (s > this.maxSize) {
                queue.removeLast();
            }
            queue.addFirst(v);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public int size() {
        return queue.size();
    }

    public Object get() {
        return get(-1);
    }

    public Object get(long timeout) {
        lock.lock();
        try {
            Object obj = null;
            for (int tryCount = 0; obj == null && tryCount < 100; tryCount++) {
                if (queue.isEmpty()) {
                    if (timeout > 0) {
                        notEmpty.await(timeout, TimeUnit.MILLISECONDS);
                        return readOne();
                    } else {
                        notEmpty.await();
                    }
                }
                obj = readOne();
            }
            return obj;
        } catch (InterruptedException e) {
            return null;
        } finally {
            lock.unlock();
        }
    }

    private Object readOne() {
        if (!queue.isEmpty()) {
            return queue.removeLast();
        } else {
            return null;
        }
    }

    public boolean isEmpty() {
        return queue.isEmpty();
    }
}




3 楼 rainshow 2008-09-23  
rainshow 写道
补充一点,使用的JAVA版本是1.5.14

已经成了过去式了,现在没办法dump了。看上有资料说ConcurrentHashMap在putAll的时候产生了deadlock,我把他的那个情况贴一下

"AWT-EventQueue-0" prio=6 tid=0x1044bba0 nid=0x2d80 in Object.wait() [0x12bbd000..0x12bbfcc8]
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:474)
at com.tc.object.lockmanager.impl.ClientLock.waitForLock(ClientLock.java:597)
- locked <0x05cf4338> (a java.lang.Object)
at com.tc.object.lockmanager.impl.ClientLock.basicLock(ClientLock.java:212)
at com.tc.object.lockmanager.impl.ClientLock.lock(ClientLock.java:117)
at com.tc.object.lockmanager.impl.ClientLock.lock(ClientLock.java:107)
at com.tc.object.lockmanager.impl.ClientLockManagerImpl.lock(ClientLockManagerImpl.java:225)
at com.tc.object.lockmanager.impl.ThreadLockManagerImpl.lock(ThreadLockManagerImpl.java:46)
at com.tc.object.tx.ClientTransactionManagerImpl.begin(ClientTransactionManagerImpl.java:181)
at com.tc.object.bytecode.ManagerImpl.begin(ManagerImpl.java:321)
at com.tc.object.bytecode.ManagerImpl.monitorEnter(ManagerImpl.java:491)
at com.tc.object.bytecode.ManagerImpl.monitorEnter(ManagerImpl.java:479)
at com.tc.object.bytecode.ManagerUtil.monitorEnter(ManagerUtil.java:482)
at java.util.concurrent.locks.ReentrantReadWriteLock$DsoLock.lock(ReentrantReadWriteLock/java:35)
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock/java)
at java.util.concurrent.ConcurrentHashMap$Segment.__tc_readLock(ConcurrentHashMap.java)
at java.util.concurrent.ConcurrentHashMap$Segment.get(ConcurrentHashMap.java:281)
at java.util.concurrent.ConcurrentHashMap.get(Unknown Source)
at net.deepvalue.ticket.TicketSharedData.getColumnValue(TicketSharedData.java:27)
at net.deepvalue.viewer.table.model.InBlotterTableModel$15.getValueAt(InBlotterTableModel.java:198)
at net.deepvalue.viewer.table.model.column.StringTicketColumn.getFormattedValueAt(StringTicketColumn.java:28)
at net.deepvalue.viewer.table.model.InBlotterTableModel.getValueAt(InBlotterTableModel.java:668)
at com.jidesoft.grid.DefaultTableModelWrapper.getValueAt(Unknown Source)
at com.jidesoft.grid.DefaultTableModelWrapper.getValueAt(Unknown Source)
at com.jidesoft.grid.DefaultTableModelWrapper.getValueAt(Unknown Source)
at javax.swing.JTable.getValueAt(JTable.java:1903)
at javax.swing.JTable.prepareRenderer(JTable.java:3911)

and the following is doing a putAll()

"pool-3-thread-358-In:BBR.A:IN_SIM:cl77461036-shareSlowPendingsCount" prio=6 tid=0x1fc60e70 nid=0x2318 waiting for monitor entry [0x29a9f000..0x29a9fc48]
at com.tc.object.tx.TransactionSequencer.addTransaction(TransactionSequencer.java:71)
- waiting to lock <0x05934bb0> (a com.tc.object.tx.TransactionSequencer)
at com.tc.object.tx.RemoteTransactionManagerImpl.commitInternal(RemoteTransactionManagerImpl.java:228)
at com.tc.object.tx.RemoteTransactionManagerImpl.commit(RemoteTransactionManagerImpl.java:218)
at com.tc.object.tx.ClientTransactionManagerImpl.commitInternal(ClientTransactionManagerImpl.java:430)
at com.tc.object.tx.ClientTransactionManagerImpl.commit(ClientTransactionManagerImpl.java:396)
at com.tc.object.tx.ClientTransactionManagerImpl.commit(ClientTransactionManagerImpl.java:335)
at com.tc.object.bytecode.ManagerImpl.monitorExit(ManagerImpl.java:510)
at com.tc.object.bytecode.ManagerUtil.monitorExit(ManagerUtil.java:502)
at java.util.concurrent.locks.ReentrantReadWriteLock$DsoLock.unlock(ReentrantReadWriteLock/java:58)
at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.unlock(ReentrantReadWriteLock/java)
at java.util.concurrent.ConcurrentHashMap$Segment.unlock(ConcurrentHashMap.java)
at java.util.concurrent.ConcurrentHashMap$Segment.put(ConcurrentHashMap.java:434)
at java.util.concurrent.ConcurrentHashMap.put(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.putAll(Unknown Source)
at net.deepvalue.ticket.TicketSharedData.setColumnValues(TicketSharedData.java:69)
at net.deepvalue.ticket.DVInboundTicket.shareSlowPendingsCount(DVInboundTicket.java:365)
at net.deepvalue.ticket.DVInboundTicket$2.run(DVInboundTicket.java:383)
at net.deepvalue.masterworker.DVWorker$2.run(DVWorker.java:287)
- locked <0x0e07deb8> (a net.deepvalue.ticket.DVInboundTicket)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:417)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask/java:267)
at java.util.concurrent.FutureTask.run(FutureTask/java:54)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
at java.lang.Thread.run(Thread.java:595)

2 楼 rainshow 2008-09-23  
补充一点,使用的JAVA版本是1.5.14
1 楼 dennis_zane 2008-09-23  
threadump出来瞧瞧了

相关推荐

    java源码剖析-ConcurrentHashMap

    ### Java源码剖析-ConcurrentHashMap #### 一、概述 `ConcurrentHashMap`是Java并发包(`java.util.concurrent`)中的一个重要组成部分,它提供了一个线程安全的哈希表实现。与传统的`Hashtable`相比,`...

    java本地缓存ConcurrentHashMap

    java本地缓存ConcurrentHashMap

    ConcurrentHashMap源码剖析

    ### ConcurrentHashMap源码剖析 #### 一、概述与背景 ConcurrentHashMap是Java中提供的一种高效、线程安全的哈希表实现。与传统的基于synchronized关键字实现线程安全的HashTable相比,ConcurrentHashMap通过采用...

    Java利用ConcurrentHashMap实现本地缓存demo

    Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~

    Java并发编程笔记之ConcurrentHashMap原理探究.docx

    Java并发编程中的ConcurrentHashMap是HashMap的一个线程安全版本,设计目标是在高并发场景下提供高效的数据访问。相比HashTable,ConcurrentHashMap通过采用锁分离技术和更细粒度的锁定策略来提升性能。HashTable...

    ConcurrentHashmap源码

    源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556

    ConcurrentHashMap源码解析

    在Java并发编程中,ConcurrentHashMap是一个重要的并发集合。它是由Doug Lea在JSR166y中引入,并在Java 5中提供的一种线程安全的HashMap实现。与传统的HashMap相比,ConcurrentHashMap在多线程环境下具有更好的性能...

    ConcurrentHashMap的实现原理

    ConcurrentHashMap 的实现原理 ConcurrentHashMap 是 Java 中一个高效的线程安全的哈希表实现,它的实现原理可以分为两部分:JDK1.7 中的实现和 JDK8 中的实现。 JDK1.7 中的实现 在 JDK1.7 中,...

    JDK1.8中ConcurrentHashMap中computeIfAbsent死循环bug.docx

    在JDK 1.8版本中,`ConcurrentHashMap`中的`computeIfAbsent`方法存在一个潜在的死循环问题。这个bug主要出现在并发操作时,当`ConcurrentHashMap`需要进行扩容并且`computeIfAbsent`正在执行计算的过程中,可能会...

    ConcurrentHashMap之实现细节

    为了防止死锁,`ConcurrentHashMap`保证了获取锁的顺序是固定的,即按照段的索引顺序依次锁定,操作完成后同样按照该顺序解锁。 #### 三、不可变性和易变性 `ConcurrentHashMap`的设计充分利用了不可变性和易变性...

    java7-8中的 HashMap和ConcurrentHashMap全解析

    在Java编程语言中,`HashMap`和`ConcurrentHashMap`是两种非常重要的数据结构,它们都属于`java.util`包,用于存储键值对。本文将深入解析这两个类在Java 7和8版本中的实现原理、特点以及使用场景。 首先,`HashMap...

    程序员面试加薪必备:ConcurrentHashMap底层原理与源码分析深入详解

    程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解

    ConcurrentHashMap思维导图完整版

    ConcurrentHashMap是J.U.C(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高效并发的版本。在默认理想状态下,ConcurrentHashMap可以支持16个线程执行并发写操作及任意数量线程的读操作。...

    java7-8中的 HashMap和ConcurrentHashMap全解析.pdf

    在Java 7和8中,HashMap和ConcurrentHashMap是两种重要的数据结构,分别用于非线程安全和线程安全的键值对存储。本篇文章将深入解析这两种数据结构的内部实现,帮助读者理解它们的工作原理。 HashMap是Java中最常用...

    高薪程序员面试题精讲系列49之说说ConcurrentHashMap#put方法的源码及数。。。.pdf,这是一份不错的文件

    ConcurrentHashMap#put方法源码解析 ConcurrentHashMap是Java并发编程中的一个重要组件,用于解决高并发情况下的数据存储问题。在面试中,ConcurrentHashMap的底层原理、put方法的实现细节都是高频考点。本文将对...

    ConcurrentHashMap的实现原理(JDK1.7和JDK1.8).pdf

    `ConcurrentHashMap`是Java并发编程中非常重要的一个数据结构,它是线程安全的HashMap实现。在理解`ConcurrentHashMap`的实现原理之前,我们先来看看哈希表的基本概念。 哈希表是一种键值对存储的数据结构,通过键...

    Java中遍历ConcurrentHashMap的四种方式详解

    Java中遍历ConcurrentHashMap的四种方式详解 Java中遍历ConcurrentHashMap的四种方式详解是Java开发中一个非常重要的知识点。ConcurrentHashMap是Java中一种高效且线程安全的HashMap实现,它提供了高效的读写操作...

Global site tag (gtag.js) - Google Analytics