Java线程转储:等待锁和停车等待之间的区别是什么?

50
在Java线程转储中,您可以在堆栈跟踪中看到锁的提及。
似乎有三种信息:

1:

- locked <0x00002aab329f7fa0> (a java.io.BufferedInputStream)

2:

=>

2:

- waiting to lock <0x00002aaaf4ff6fa0> (a org.alfresco.repo.lock.LockServiceImpl)

3:

- parking to wait for  <0x00002aaafbf70bb8> (a java.util.concurrent.SynchronousQueue$TransferStack)
  • 1: 该线程已经获得了对象0x00002aab329f7fa0的锁。
  • 2&3:似乎表明该线程正在等待该对象上的锁变为可用状态...但是2和3有什么区别?

我问这个问题是因为我正在尝试修复这个有前途的开源锁可视化工具:https://gist.github.com/3039126 - Nicolas Raoul
2个回答

51

如果使用内在锁,则线程转储中会出现“等待锁定”(waiting to lock);如果使用java.util.concurrent中的锁,则会出现“等待停放”(parking to wait for)。请考虑以下示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

    final Lock lock = new ReentrantLock(true);

    synchronized void intrinsicLock() {
        Thread th = new Thread(new Runnable() {
            public void run() {
                intrinsicLock();
            }
        }, "My thread");
        th.start();
        try {
            th.join();
        } catch (InterruptedException e) {
        }
    }

    void reentrantLock() {
        lock.lock();
        Thread th = new Thread(new Runnable() {
            public void run() {
                reentrantLock();
            }
        }, "My thread");
        th.start();
        try {
            th.join();
        } catch (InterruptedException e) {
        }
        lock.unlock();
    }


    public static void main(String[] args) {
        LockTest lockTest = new LockTest();
        lockTest.intrinsicLock();
        //lockTest.reentrantLock();
    }

}

使用 lockTest.intrinsicLock() 将会得到以下线程转储:

"My thread" prio=10 tid=0x00007fffec015800 nid=0x1775 waiting for monitor entry [0x00007ffff15e5000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at LockTest.intrinsicLock(LockTest.java:9)
    - waiting to lock <0x00000007d6a33b10> (a LockTest)
    at LockTest$1.run(LockTest.java:11)
    at java.lang.Thread.run(Thread.java:662)

当调用lockTest.reentrantLock()时会产生:

"My thread" prio=10 tid=0x00007fffec082800 nid=0x17e8 waiting on condition [0x00007ffff14eb000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007d6a33d30> (a java.util.concurrent.locks.ReentrantLock$FairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:842)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1178)
    at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:201)
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
    at LockTest.reentrantLock(LockTest.java:22)
    at LockTest$2.run(LockTest.java:25)
    at java.lang.Thread.run(Thread.java:662)

25
这两个州之间有什么“区别”? - aayoubi

3

我认为,java.util.concurrent包中的大部分类都使用LockSupport.park()方法来阻塞线程,比如CountDownLatch、ReentrantLock等都属于abstractqueuedsynchronized框架。 因此,在你提出的问题中,第三种情况意味着你的代码最终调用了LockSupport.park()方法,因为你使用了java.util.concurrent包中的并发类;而第二种情况则意味着你使用了synchronized关键字,并显式地调用了wait()方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接