我正在考虑从synchronized
切换到ReadWriteLock
。在做之前,我想检查它是否值得。
ThreadMXBean
和ThreadInfo
提供有关整体线程阻止计数和时间的信息。这些块可能由多个监视器引起。有没有办法在给定特定监视器对象的情况下测量块统计信息?
答案 0 :(得分:3)
是的,可以使用JVMTI。
您需要编写一个处理一对事件的本机代理:
这两个事件都接受jthread
和jobject
个参数,这些参数对应于获取监视器和监视器对象本身的线程。
Here is争用探查器代理的示例代码。
答案 1 :(得分:3)
答案 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);
}
}