2016-07-05 6 views
3

synchronized에서 ReadWriteLock으로 전환하는 것이 좋습니다. 그것을하기 전에, 나는 그것이 가치가 있는지 확인하고 싶습니다.특정 모니터에서 스레드 경합 측정

ThreadMXBeanThreadInfo은 전체 스레드 차단 횟수 및 시간에 대한 정보를 제공합니다. 이러한 블록은 다중 모니터로 인해 발생할 수 있습니다. 특정 모니터 객체가 주어진 경우 블록 통계를 측정하는 방법이 있습니까?

+0

감사합니다. jconsole과 visualvm 만 알고 있었고 잠금 경합 정보를 제공하지 않았습니다. jmc는 내가 원하는 것처럼 보입니다. 아래에 답변을 게시 할 수 있습니까? – damluar

답변

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); 
    } 
} 
+1

내 질문에 어떻게 대답합니까? – damluar

+0

주기적으로 차단 된 스레드 대기열 (초당 100 회)을 검사하고 통계를 수집 할 수 있습니다. –

+0

내 질문에, 나는 그것이 가치가 있는지 확인하기 전에 전환하고 싶지 않다고 설명했다. – damluar

3

예, JVMTI을 사용할 수 있습니다.

는 무엇입니까 당신이 필요로하는 것은 사건의 한 쌍의 처리 원시 에이전트 작성하는 것입니다 :

  • MonitorContendedEnter - 스레드가 이미 다른 스레드에 의해 인수 syncrhonized 블록을 입력하려고 할 때 해고를;
  • MonitorContendedEntered - 스레드가 대기 후 모니터를 성공적으로 획득하면 시작됩니다.

두 이벤트는 모니터와 모니터 개체 자체를 획득 스레드에 해당 jthreadjobject 인수를 받아들입니다.


Here is 경합 프로파일 러 에이전트의 샘플 코드.