無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

JDIでスレッドダンプを取得する。

JDI(Java Debug Interface)でスレッドダンプをとります。

  • JDIは、その名の通り、仮想マシンのデバッガや類似システムに有用な情報を提供するJava API です。
  • リモートからのデバッグを標準でサポートしています。
  • JDK添付ですが、実装はtools.jar内にあります。利用するにはtools.jarをクラスパスに通す必要があります。(/lib以下にあります。)
プログラム
import java.io.IOException;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.sun.jdi.Bootstrap;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.Connector.IntegerArgument;
import com.sun.jdi.connect.Connector.StringArgument;

/**
 * JDIが提供するAPIを使用してスレッドダンプをとります。<br/>
 * 結果は標準出力に出力されます。
 * <p>
 *  usage : java ThreadDump [host] [port]
 * </p>
 * <p>
 *  <b>使用方法</b>
 * </p>
 * <ol>
 *  <li>
 *    以下のVM引数を指定して、ダンプ対象となるJavaVMを起動しておく。
 *    <pre>-Xrunjdwp:transport=dt_socket,address=8009,server=y,suspend=n</pre>
 *    ※ポート番号は重複しなければ任意の値でOK。
 *  </li>
 *  <li>VMが起動しているホスト名、使用するポートを指定してツールを起動する。</li>
 * </ol>
 */
public class ThreadDump {

    /** vm */
    private VirtualMachine vm;

    /** ログの出力先 */
    private final PrintStream out;

    /***
     * コンストラクタ
     * @param out 出力先
     */
    public ThreadDump ( PrintStream out ) {
        this.out = out;
    }


    /***
     * メイン関数
     * @param args 引数
     * @throws IncompatibleThreadStateException
     * @throws IllegalConnectorArgumentsException
     * @throws IOException
     * @throws NumberFormatException
     */
    public static void main ( String[] args )
    throws NumberFormatException, IOException,
    IllegalConnectorArgumentsException, IncompatibleThreadStateException {
        ThreadDump td = new ThreadDump(System.out);
        td.connect(args[0], Integer.parseInt(args[1]));
        td.dump();
    }

    /**
     * デバッグ対象vmに接続します。
     * @param host 接続先ホスト
     * @param port 接続先ポート
     * @throws IOException
     * @throws IllegalConnectorArgumentsException
     * @throws IncompatibleThreadStateException
     */
    public void connect(String host, int port)
    throws IOException, IllegalConnectorArgumentsException,
            IncompatibleThreadStateException {

        VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
        List acs = vmm.attachingConnectors();

        // 一覧からソケットコネクタを探す。
        AttachingConnector ac = null;
        Iterator it = acs.iterator();
        while (it.hasNext()) {
            AttachingConnector tmp = (AttachingConnector)  it.next();
            // ソケットコネクタを探す。
            if ("com.sun.jdi.SocketAttach".equals(tmp.name())) {
               ac = tmp;
               break;
            }
        }

        //引数を設定して接続
        Map arg = ac.defaultArguments();
        IntegerArgument portNumber =
            ( IntegerArgument ) arg.get("port");
        portNumber.setValue(port);
        StringArgument hostname =
            ( StringArgument ) arg.get("hostname");
        hostname.setValue(host);
        vm = ac.attach( arg );
    }

    /**
     * スレッドダンプを取ります。
     */
    void dump() {
        List list = vm.allThreads();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            ThreadReference tr = (ThreadReference) it.next();
            try {
                tr.suspend();
                printThreadInfo(tr);
            } finally {
                if (tr.isSuspended()) {
                    tr.resume();
                }
            }
        }
    }

    /**
     * スレッドの情報を標準出力に出力します。
     * @param tr スレッド参照
     */
    private void printThreadInfo( ThreadReference tr ) {
        out.println( "" );
        out.println( "----");
        printInfo("name", tr.name());

        // 状態
        String status = convStatusToString(tr.status());
        printInfo("status", status);

        // カレントのロックを取得
        ObjectReference or = null;
        try {
            or = tr.currentContendedMonitor();
        } catch ( IncompatibleThreadStateException e ) {
            e.printStackTrace();
            return;
        }
        String lock = toTypeStr(or);
        printInfo("current contended monitor", lock != null ? lock : "none..");

        // ロックを保持しているオブジェクトの一覧を取得
        List list = null;
        try {
            list = tr.ownedMonitors();
        } catch ( IncompatibleThreadStateException e ) {
            e.printStackTrace();
            return;
        }
        Iterator oit = list.iterator();
        StringBuffer locked = new StringBuffer();
        while (oit.hasNext()) {
            or = ( ObjectReference) oit.next();
            lock = toTypeStr(or);
            locked.append(lock != null ? lock : "unknown..");
            if (!oit.hasNext()) {
                locked.append("\n  ");
            }
        }
        if (locked.toString().length() <= 0) {
            locked.append("none..");
        }
        printInfo("owned monitors", locked.toString());

        // フレーム一覧を出力
        out.println( "stack-trace :" );
        List frames = null;
        try {
            frames = tr.frames();
        } catch ( IncompatibleThreadStateException e ) {
            e.printStackTrace();
            return;
        }
        Iterator fit  = frames.iterator();
        while (fit.hasNext()) {
            StackFrame sf = ( StackFrame ) fit.next();
            out.println( "  " + sf.location() );
        }
    }

    /**
     * ステータスIDを表示用文字列に変換します。
     * @param status ステータスID
     * @return ステータスの表示用文字列
     */
    private static String convStatusToString ( int status ) {
        String str = "";
        switch (status) {
            case ThreadReference.THREAD_STATUS_MONITOR :
                str =  "waiting monitor";
                break;
            case ThreadReference.THREAD_STATUS_NOT_STARTED :
                str =  "not started";
                break;
            case ThreadReference.THREAD_STATUS_RUNNING :
                str =  "running";
                break;
            case ThreadReference.THREAD_STATUS_SLEEPING :
                str =  "sleeping";
                break;
            case ThreadReference.THREAD_STATUS_WAIT :
                str =  "wait";
                break;
            case ThreadReference.THREAD_STATUS_ZOMBIE:
                str =  "zombie";
                break;
            case ThreadReference.THREAD_STATUS_UNKNOWN :
            default:
                str =  "unknown";
        }
        return str;
    }

    /**
     * オブジェクト参照の種類を示す文字列を取得します。
     * @param or オブジェクト参照
     * @return オブジェクトの種類を示す文字列
     */
    private static String toTypeStr(ObjectReference or) {
        if (or != null) {
            ReferenceType rt = or.referenceType();
            return rt.name() + " (id=" +or.uniqueID() + ")";
        } else {
            return null;
        }
    }

    private void printInfo(String title, String value) {
        out.println( title + " :\n  " + value);
    }
}
使用方法

プログラム中のコメントの通りです。

  1. 以下のVM引数を指定して、ダンプ対象となるJavaVMを起動しておきます。
    • -Xrunjdwp:transport=dt_socket,address=8009,server=y,suspend=n
    • ※ポート番号は重複しなければ任意の値でOK。
  2. VMが起動しているホスト名、使用するポートを指定してツールを実行します。
出力例
----
name :
  DestroyJavaVM
status :
  running
current contended monitor :
  none..
owned monitors :
  none..
stack-trace :

----
name :
  AWT-EventQueue-0
status :
  wait
current contended monitor :
  java.awt.EventQueue (id=10)
owned monitors :
  none..
stack-trace :
  java.lang.Object.wait(long)+-1
  java.lang.Object:474
  java.awt.EventQueue:345
  java.awt.EventDispatchThread:189
  java.awt.EventDispatchThread:163
  java.awt.EventDispatchThread:157
  java.awt.EventDispatchThread:149
  java.awt.EventDispatchThread:110

----
name :
  AWT-Shutdown
status :
  wait
current contended monitor :
  java.lang.Object (id=14)
owned monitors :
  none..
stack-trace :
  java.lang.Object.wait(long)+-1
  java.lang.Object:474
  sun.awt.AWTAutoShutdown:259
  java.lang.Thread:595

----
name :
  Java2D Disposer
status :
  wait
current contended monitor :
  java.lang.ref.ReferenceQueue$Lock (id=17)
owned monitors :
  none..
stack-trace :
  java.lang.Object.wait(long)+-1
  java.lang.ref.ReferenceQueue:116
  java.lang.ref.ReferenceQueue:132
  sun.java2d.Disposer:107
  java.lang.Thread:595

----
name :
  AWT-Windows
status :
  running
current contended monitor :
  none..
owned monitors :
  none..
stack-trace :
  sun.awt.windows.WToolkit.eventLoop()+-1
  sun.awt.windows.WToolkit:269
  java.lang.Thread:595

----
name :
  Signal Dispatcher
status :
  running
current contended monitor :
  none..
owned monitors :
  none..
stack-trace :

----
name :
  Finalizer
status :
  wait
current contended monitor :
  java.lang.ref.ReferenceQueue$Lock (id=22)
owned monitors :
  none..
stack-trace :
  java.lang.Object.wait(long)+-1
  java.lang.ref.ReferenceQueue:116
  java.lang.ref.ReferenceQueue:132
  java.lang.ref.Finalizer$FinalizerThread:159

----
name :
  Reference Handler
status :
  wait
current contended monitor :
  java.lang.ref.Reference$Lock (id=24)
owned monitors :
  none..
stack-trace :
  java.lang.Object.wait(long)+-1
  java.lang.Object:474
  java.lang.ref.Reference$ReferenceHandler:116