LockSupport.park(Object)是否释放阻止对象的监视锁定

时间:2014-01-27 08:21:45

标签: java concurrency

我正在尝试断言是否使用LockSupport.park(Object blocker)重新发布阻止程序的监视器锁定对象。也就是说:如果在blocker上同步的部分中调用,blocker的监视器锁定是否会被释放?

这是我做的一个junit测试,让我认为是这样的。

我知道一个线程处于状态WAITING,因为调用了Òbject.waitor LockSupport.park(),它看起来像使用了相同的底层机制。但是,javadoc没有明确说明我的问题,所以我不确定。

final Object blocker    = new Object();
final Thread thread     = new Thread() {

    @Override
    public void run() {
        synchronized(blocker) {
            while(!interrupted()) {
                assertTrue(holdsLock(blocker));
                LockSupport.park(blocker);
            }
        }
    }
};
try {
    thread.start();
    while(thread.getState() != Thread.State.WAITING)
        Thread.sleep(100);
    assertEquals(0, ManagementFactory.getThreadMXBean().getThreadInfo(thread.getId()).getLockedMonitors().length);
} finally {
    thread.interrupt();
}

3 个答案:

答案 0 :(得分:2)

简单的答案是否定的。 LockSupport不适用于一般应用程序编程。由于没有保护(与同步等待/通知一起提供),您需要明确控制整个线程环境。也就是说,您不能使用第三方软件并期望它符合您的标准。

有关如何使用park / unpark查看ForkJoinPool源代码的一个很好的示例。

答案 1 :(得分:1)

首先,只需使用以下代码,您的代码就有缺陷了:

ManagementFactory.getThreadMXBean().getThreadInfo(thread.getId())

如文档中所述(它表示此方法等效于调用getThreadInfo(id, 0),而后者称为)

  

...未获得线程的锁定监视器和锁定同步器

因此该数组的长度始终为零。

因此,如果您想要明智的验证代码:

   public class DeleteMe3 {

    public static void main(String[] args) {

        Object lock = new Object();
        System.out.println(lock.toString());
        Thread thread = new Thread() {

            @Override
            public void run() {
                synchronized (lock) {
                    boolean holdLock = Thread.holdsLock(lock);
                    if (!holdLock) {
                        throw new AssertionError("Does not hold lock");
                    } else {
                        System.out.println("I hold the lock");
                    }
                    System.out.println("Before parking");
                    LockSupport.park(lock);

                }
            }
        };

        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        showIfAnyLocksHeld(thread.getId());

        System.out.println("Unparking... ");
        LockSupport.unpark(thread);

    }

    private static void showIfAnyLocksHeld(long threadId) {

        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] infos = bean.getThreadInfo(new long[] { threadId }, true, true);
        if (infos.length == 0) {
            System.out.println("Thread we are interested in has died");
            return;
        }

        MonitorInfo[] mInfos = infos[0].getLockedMonitors();
        if (mInfos.length == 0) {
            System.out.println("No locks held by thread " + threadId);
            return;
        }

        System.out.println("Thread with id = " + threadId + " holds lock(s) : " +
                Arrays.stream(mInfos).map(MonitorInfo::toString).collect(Collectors.joining(" ; ")));
    }

}

输出将包含:

 java.lang.Object@5f2108b5
 I hold the lock
 Before parking
 Thread with id = 12 holds lock(s) : java.lang.Object@5f2108b5

因此,您可以说LockSupport.park释放锁;但是如果这样做的话,那将是很奇怪的。除非将其记录下来,否则不会记录。

答案 2 :(得分:0)

如果javadoc没有定义行为,则它是未定义的;)

不要依赖它。