2016-07-05 9 views
3

​​からReadWriteLockに切り替えることを検討しています。それを行う前に、それがその価値があるかどうかチェックしたいと思います。特定のモニタでスレッドの競合を測定する

ThreadMXBeanおよびThreadInfoは、全体的なスレッドブロックカウントおよび時間に関する情報を提供します。これらのブロックは、複数のモニターによって発生する可能性があります。特定のモニターオブジェクトを指定してブロック統計を測定する方法はありますか?

+0

ありがとう、私はjconsoleとvisualvmだけに精通していて、ロックの競合情報を提供していません。 jmcは私が欲しいもののように見えます。あなたはあなたの答えを以下に投稿できますか? – damluar

答えて

0

ReentrantReadWriteLockの内部カーネル - タイプAbstractQueuedSynchronizer(AQS)のプライベートフィールド 'sync'。 AQS - Doug Leaの最もシンクロナイザーの1つ。これには、競合スレッドの単一リンクリストが含まれています。マークされたすべてのスレッドは「排他的」または「共有」です。 詳細については"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競合プロファイラエージェントのサンプルコードです。

関連する問題