测量特定监视器上的线程争用

时间:2016-07-05 16:36:35

标签: java multithreading jvm jconsole jvisualvm

我正在考虑从synchronized切换到ReadWriteLock。在做之前,我想检查它是否值得。

ThreadMXBeanThreadInfo提供有关整体线程阻止计数和时间的信息。这些块可能由多个监视器引起。有没有办法在给定特定监视器对象的情况下测量块统计信息?

3 个答案:

答案 0 :(得分:3)

是的,可以使用JVMTI

您需要编写一个处理一对事件的本机代理:

这两个事件都接受jthreadjobject个参数,这些参数对应于获取监视器和监视器对象本身的线程。

Here is争用探查器代理的示例代码。

答案 1 :(得分:3)

jmcyourkitjprofiler都提供锁争用分析。

答案 2 :(得分:0)

ReentrantReadWriteLock的内部内核 - 类型为AbstractQueuedSynchronizer(AQS)的私有字段“sync”。 AQS-- Doug Lea最伟大的“同步器”之一。它包含竞争线程的单链接列表。标记的每个主题都是“独占”或“共享”。 阅读更多信息"The java.util.concurrent Synchronizer Framework"

您可以定期检查被阻止的线程队列(每秒100次)并收集统计信息。

import java.lang.reflect.Field;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class App {
    static final AtomicInteger freeTime = new AtomicInteger(0);
    static final AtomicInteger fullTime = new AtomicInteger(0);
    static final AtomicInteger readersLength = new AtomicInteger(0);
    static final AtomicInteger writersLength = new AtomicInteger(0);

    public static float contended() {
        return fullTime.get() / (fullTime.get() + freeTime.get());
    }

    public static float uncontended() {
        return freeTime.get() / (fullTime.get() + freeTime.get());
    }

    public static float meanReadersQueue() {
        return readersLength.get() / fullTime.get();
    }

    public static float meanWritersQueue() {
        return writersLength.get() / fullTime.get();
    }

    public static void main(String[] args) throws Exception {
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
        AbstractQueuedSynchronizer sync =
                useReflection(lock, "sync", AbstractQueuedSynchronizer.class);

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            int queueLength = sync.getQueueLength();
            if (queueLength == 0) {
                freeTime.incrementAndGet();
            } else {
                fullTime.incrementAndGet();
                int readersCount = sync.getSharedQueuedThreads().size();
                readersLength.addAndGet(readersCount);
                int writersCount = sync.getExclusiveQueuedThreads().size();
                writersLength.addAndGet(writersCount);
            }
        }, 0, 10, TimeUnit.MILLISECONDS);
    }

    private static <T> T useReflection(Object from, String name, Class<T> to) throws Exception {
        Field f = from.getClass().getDeclaredField(name);
        f.setAccessible(true);
        return (T) f.get(from);
    }
}