论坛首页 入门技术论坛

ConcurrentHashMap死锁的疑惑

浏览 7616 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-09-23  
最近在使用ConcurrentHashMap的过程中,发现ConcurrentHashMap在一定的条件下会导致死锁(这个条件目前还不知道到底什么,我的ConcurrentHashMap多个线程共享,会删除和增加一些数据到ConcurrentHashMap对象里)

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

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

这个问题很奇怪,虽然现在解决了,还是不明白什么情况下会导致ConcurrentHashMap死锁呢?
   发表时间:2008-09-23  
threadump出来瞧瞧了
0 请登录后投票
   发表时间:2008-09-23  
补充一点,使用的JAVA版本是1.5.14
0 请登录后投票
   发表时间: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)

0 请登录后投票
   发表时间: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();
    }
}




  • 大小: 22.1 KB
0 请登录后投票
   发表时间:2008-09-23  
ConcurrentHashMap用的是似有锁,用户拿不到锁对象,怎么会死锁阿
0 请登录后投票
   发表时间:2008-09-24  
cpu占用那么多,说明是死循环,比如HashMap在多线程下,get操作有可能陷入死循环,注意这种要求同步的访问。
0 请登录后投票
   发表时间: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的引用是很有可能被派发到多个线程里去的。
0 请登录后投票
   发表时间:2008-12-14  
1.多线程使用HashMap,有死循环的问题,我遇到过两次了。
2.我现在用的也是ConcurrentHashMap,并发量很大,没遇到什么问题。
0 请登录后投票
   发表时间:2009-02-26  
我倒,putAll可不是太好的操作。你的设计完全是有问题的。
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics