Java多线程应用程序:获取线程阻塞时间

3
我在工作线程结束之前调用了 threadInfo.getBlockedCount()getBlockedTime() 方法。我得到的阻塞计数是1,但阻塞时间为0。这是否意味着线程被阻塞,但阻塞时间少于一毫秒?
如果以上内容属实,那么是否有其他方法可以准确获取线程被阻塞的时间?
4个回答

2
然而,线程被阻塞的时间(被阻塞)似乎只有在在启动线程之前调用ThreadMXBean#setThreadContentionMonitoringEnabled(true)时才会返回非零结果。否则,它将始终返回零(如果争用监测已禁用,则返回-1)。下面的代码演示了这一点:
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class BlockedTimeMain {
    public static void main(String[] _) throws InterruptedException  {
        ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
        final Object lock = new Object();

        Thread t = new Thread("Foo") {
            @Override public void run() {
                // This will block forever
                synchronized(lock) {
                    // Will never get here
                    System.out.println("Got the lock from " + Thread.currentThread());
                }
            }
        };
        synchronized(lock) {
            t.start();
            mbean.setThreadContentionMonitoringEnabled(true);
            for (int i=0; i < 5; i++) {
                ThreadInfo[] tis = mbean.getThreadInfo(new long[]{t.getId()}, true, true);
                ThreadInfo ti = tis[0];

                if (ti.getThreadId() != t.getId())
                    throw new AssertionError("Unexpected " + t.getId() + " vs " + tis[0].getThreadId());

                System.out.println(t + " " + ti.getThreadState() 
                        + ": blockedTime=" + ti.getBlockedTime() + "/" + ti.getBlockedCount() 
                        + ", waitTime" + ti.getWaitedTime() + "/" + ti.getWaitedCount());
                Thread.sleep(1000);
            }
        }
        System.exit(0);
    }
}

示例输出:

Thread[Foo,5,main] BLOCKED: blockedTime=0/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=0/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=0/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=0/1, waitTime0/0

1

可以用类似以下的方式进行测试:

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class BlockedTimeMain {
    public static void main(String[] _) throws InterruptedException  {
        ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
        mbean.setThreadContentionMonitoringEnabled(true);
        final Object lock = new Object();

        Thread t = new Thread("Foo") {
            @Override public void run() {
                // This will block forever
                synchronized(lock) {
                    // Will never get here
                    System.out.println("Got the lock from " + Thread.currentThread());
                }
            }
        };
        synchronized(lock) {
            t.start();
            for (;;) {
                ThreadInfo[] tis = mbean.getThreadInfo(new long[]{t.getId()}, true, true);
                ThreadInfo ti = tis[0];

                if (ti.getThreadId() != t.getId())
                    throw new AssertionError("Unexpected " + t.getId() + " vs " + tis[0].getThreadId());

                System.out.println(t + " " + ti.getThreadState() 
                        + ": blockedTime=" + ti.getBlockedTime() + "/" + ti.getBlockedCount() 
                        + ", waitTime" + ti.getWaitedTime() + "/" + ti.getWaitedCount());
                Thread.sleep(1000);
            }
        }
    }
}

样例输出:

Thread[Foo,5,main] BLOCKED: blockedTime=2/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=1007/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=2012/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=3016/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=4021/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=5025/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=6028/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=7032/1, waitTime0/0
Thread[Foo,5,main] BLOCKED: blockedTime=8035/1, waitTime0/0

0

是的,它确实意味着它被阻塞了0毫秒。也就是说,没有阻塞涉及其中。线程没有等待监视器锁定以进入同步块/方法。

您看到这是因为您必须编写了一个只有一两个线程的简单程序,并且没有延迟。您需要对线程施加真正的重负载才能看到正值。


0

显然,这就是它的意思,而且似乎没有办法使时间精度更高。(Javadoc说阻塞时间可以被测量和(可能)累积更高的精度,但ThreadInfo API不公开此信息,也没有其他合法的方法来获取它。)

我说“似乎”,因为Javadoc实际上将时间值描述为“近似的累计经过时间”。这留下了可能是非常粗略的近似值的可能性,可能与System.getCurrentTimeMillis()返回的时钟值具有相同的粒度。此外,它没有说明使用高精度计时器测量的累计时间在转换为毫秒值时是否会四舍五入或截断;即零是否表示“小于1毫秒”或“小于0.5毫秒”。


请将此更改为 System.currentTimeMillis() - asgs

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