今天线上的tomcat线程全部被吃完,通过jstack查看线程信息,发现有很多线程在等待锁对象,有大量的线程卡在ConnectionPoolImpl的484行,而且都是在 waiting to lock <0x0000000780fd06f8>,如下:"http-bio-8118-exec-1" daemon prio=10 tid=0x00007fbd68001800 nid=0xb78 waiting for monitor entry [0x00007fbe66140000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.seasar.extension.dbcp.impl.ConnectionPoolImpl.checkInTx(ConnectionPoolImpl.java:484)
        - waiting to lock <0x0000000780fd06f8> (a org.seasar.extension.dbcp.impl.ConnectionPoolImpl)
        at org.seasar.extension.dbcp.impl.ConnectionWrapperImpl.close(ConnectionWrapperImpl.java:283)
        at org.seasar.extension.jdbc.manager.JdbcContextImpl.destroy(JdbcContextImpl.java:104)
        …………ConnectionPoolImpl的484行代码如下
然后查看到底是哪个线程获得了0x0000000780fd06f8这个锁对象,发现了如下一个线程:"http-bio-8118-exec-3" daemon prio=10 tid=0x00007fbd68004800 nid=0xb7a waiting for monitor entry [0x00007fbe65f3e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.seasar.extension.dbcp.impl.ConnectionPoolImpl.checkInTx(ConnectionPoolImpl.java:484)
        - locked <0x00000007864498a8> (a org.seasar.extension.dbcp.impl.ConnectionPoolImpl)
        at org.seasar.extension.dbcp.impl.ConnectionWrapperImpl.close(ConnectionWrapperImpl.java:283)
        at org.seasar.extension.jdbc.manager.JdbcContextImpl.destroy(JdbcContextImpl.java:104)
         …………问题来了,既然这个线程获得了0x00000007864498a8这个锁对象并加锁了,为什么还BLOCKED在ConnectionPoolImpl.java:484行呢?,既然线程是BLOCKED,那他又是在等待哪个锁对象呢?(等待锁对象时,不是线程信息里面都会有waiting to lock <0x...........>信息吗?),请大神指教和交流~ps:间隔一段时间后再运行jstack命令,http-bio-8118-exec-3线程的状态一直都没变过为了验证我的想法,写了一个测试程序,运行后,使用jsatck查看线程信息:
main方法:public static void main(String[] args) throws Exception {
        Lock l = new Lock();
        new TestThread(l).start();new TestThread(l).start();
        new TestThread(l).start();new TestThread(l).start();
        new TestThread(l).start(); new TestThread(l).start();
    }
}Class:Lockpublic class Lock{
    public synchronized void test(){
        System.out.println("in"+Thread.currentThread().getName());
        try { Thread.sleep(260000L); } catch (InterruptedException e) { }
    }
}Class:TestThread :class TestThread extends Thread{
    Lock lock;
    public TestThread(Lock lock){
        this.lock = lock;
    }
    @Override
    public void run() {
        lock.test();
    }
}然后是jstack命令返回的线程信息:其中1号线程获取了Lock的锁对象,然后进入Sleep,线程变为TIMED_WAITING状态,其他线程都在等待Lock对象,0x23a568a0;通过查看dump下来的内存,0x23a568a0这个对象正是在main方法里面new出来的那个lock

解决方案 »

  1.   

    dbcp连接池开了多少?查看下连接池情况,看是否都被占用?顺便看下空闲连接个数是多少。
      

  2.   

    ConnectionPoolImpl 里还有其他 什么同步方法呢?sleep是不释放锁的。
      

  3.   

    是的,就因为sleep不释放锁,所以我写个测试让一个线程一直拥有所,其他线程被阻塞时,通过jstack命令查看线程信息是什么情况,事实来看,被阻塞的线程情况跟线上项目的线程情况一样,都是在waiting to lock xxxx对象,而获得锁的那个线程是locked xxx对象。
    ConnectionPoolImpl 里面也没有其他同步方法了。
    连接池开的40个;主要在意的是为什么那个线程获得锁对象了,线程还是BLOCK状态,而且也没显示等待哪个对象。所以没太关注连接池情况,得等明天再重现了这个问题看看;
      

  4.   

         …………
    是的,就因为sleep不释放锁,所以我写个测试让一个线程一直拥有所,其他线程被阻塞时,通过jstack命令查看线程信息是什么情况,事实来看,被阻塞的线程情况跟线上项目的线程情况一样,都是在waiting to lock xxxx对象,而获得锁的那个线程是locked xxx对象。
    ConnectionPoolImpl 里面也没有其他同步方法了。
    连接池开的40个;主要在意的是为什么那个线程获得锁对象了,线程还是BLOCK状态,而且也没显示等待哪个对象。所以没太关注连接池情况,得等明天再重现了这个问题看看;

    我网上找了个类似的源代码看看,好几个同步方法呢。
      

  5.   

    你上面发的locked和waiting to lock不是同一个id。
      

  6.   


    哦,失误了,应该是截错图了。当时确实有很多线程在等待0x00000007864498a8这个对象。待会再上个图。那还如直接把所有的 stack都贴上来呢。