我正在考虑从synchronized
切换到ReadWriteLock
。在此之前,我想检查是否值得这样做。
ThreadMXBean
和 ThreadInfo
提供有关线程总阻塞次数和时间的信息。这些阻塞可能由多个监视器引起。是否有一种方法可以测量给定特定监视器对象的阻塞统计信息?
我正在考虑从synchronized
切换到ReadWriteLock
。在此之前,我想检查是否值得这样做。
ThreadMXBean
和 ThreadInfo
提供有关线程总阻塞次数和时间的信息。这些阻塞可能由多个监视器引起。是否有一种方法可以测量给定特定监视器对象的阻塞统计信息?
是的,使用JVMTI是可能的。
你需要编写一个本地代理程序来处理一对事件:
这两个事件都接受jthread
和jobject
参数,对应于获取监视器的线程和监视器对象本身。
ReentrantReadWriteLock 的内部内核 - 类型为 AbstractQueuedSynchronizer (AQS) 的私有字段 'sync'。 AQS 是 Doug Lea 最伟大的“同步器”之一。它包含争用线程的单向链表。每个线程都标记为“独占”或“共享”。 了解更多信息 "java.util.concurrent 同步器框架"。
您可以定期检查阻塞的线程队列(每秒 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);
}
}