1. ホーム
  2. ジャワ

JavaスレッドのThreadクラス詳細説明

2022-02-24 12:41:51
<パス

Threadクラスはスレッドを操作するために使用され、スレッドを含むすべての操作(並行処理など)の基礎となるものである。今回は、ソースコードを通してThreadクラスの機能的な役割を分析します。

I. プロパティ

    /* Make sure registerNatives is the first thing 
 does. */

    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int priority;
    private Thread threadQ;
    private long eetop;

    /* Whether or not to single_step this thread. */
    private boolean single_step;

    /* Whether or not the thread is a daemon thread.
    private boolean daemon = false;

    /* JVM state */
    private boolean stillborn = false;

    /* What will be run. */
    private Runnable target;

    /* The group of this thread */
    private ThreadGroup group;

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;

    /* The inherited AccessControlContext of this thread */
    private AccessControlContext inheritedAccessControlContext;

    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * This map is maintained * by the ThreadLocal class.
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocalMap threadLocals = null; /*
     ThreadLocalMap threadLocals = null; /* InheritableThreadLocal values pertaining to this thread.
     This map is * maintained by the InheritableThreadLocal class.
     This map is * maintained by the InheritableThreadLocal class. */

    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

    /*
     * The requested stack size for this thread, or 0 if the creator did
     It is up to the VM to do whatever it * likes with this number; some VMs do * not specify a stack size.
     * It is up to the VM to do whatever it likes with this number; some VMs will ignore it.
     */It is up to the VM to do whatever it likes with this number; some VMs will ignore it.
    private long stackSize;

    private stackSize; /*
     * JVM-private state that persists after native thread termination.
     */
    private long nativeParkEventPointer;

    /*
     * Thread ID
     */
    private long tid;

    /* For generating thread ID */
    private static long threadSeqNumber;

    /* Java thread status for tools,
     * initialized to indicate thread 'not yet started'
     */private

    private volatile int threadStatus = 0;
  volatile Object parkBlocker;

    /* The object in which this thread is blocked in an interruptible I/O * operation, if any.
     * The blocker's interrupt method should be invoked
     The blocker's interrupt method should be invoked * after setting this thread's interrupt status.
     */
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();

    public final static int MIN_PRIORITY = 1;

    /* The default priority that is assigned to
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;
    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /** * Thread state for a runnable thread.
         * Thread state for a runnable thread.
         A thread in the runnable * state is executing in the Java virtual machine but it may
         A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system
         A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor.
         */RUNNABLE, RUNNABLE
        RUNNABLE,

        RUNNABLE, /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * The following methods:
         * 
    *
  • {@link Object#wait() Object.wait} with no timeout
  • *
  • {@link #join() Thread.join} with no timeout
  • *
  • {@link LockSupport#park() LockSupport.park}
  • *
* *

A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called Object.wait() * on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on * A thread that has called Thread.join() * is waiting for a specified thread to terminate. */

WAITING, /* * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: *
    *
  • {@link #sleep Thread.sleep}
  • *
  • {@link Object#wait(long) Object.wait} with timeout
  • *
  • {@link #join(long) Thread.join} with timeout
  • *
  • {@link LockSupport#parkNanos LockSupport.parkNanos}
  • *
  • {@link LockSupport#parkUntil LockSupport.parkUntil}
  • *
*/ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; TERMINATED; }

ここでは、スレッドの優先順位と状態に焦点を当てます。

1. スレッドの優先順位


    private int priority;

    public final static int MIN_PRIORITY = 1;
    public final static int NORM_PRIORITY = 5;
    public final static int MAX_PRIORITY = 10;

   public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) ! = null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

    public final int getPriority() {
        return priority;
    }

スレッドの実行には優先順位があり、優先順位が高いほど最初に実行される確率が高くなります(必ずしも最初に実行されるとは限りません!!)。 . 優先順位は、int型のpriorityパラメータで表されます。
スレッドの優先度は、最大10、最小1です。
2. スレッドの状態

 public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }
      public State getState() {
        return sun.misc.VM.toThreadState(threadStatus);
    }

Threadオブジェクトは6つの状態を持っています。NEW(新規)、RUNNABLE(実行中)、BLOCKED(ブロック中)、WAITING(待機中)、TIMED_WAITING(時間待ち)、TERMINATED(終了中)であり、状態の遷移は以下の通りである。

議論もあり、これもありだと思います。
スレッドは "ready", "blocking", "running" だけです(新しい [NEW]" と " TERMINATED]" 状態はスレッドではなく、単にスレッド オブジェクトがまだ存在しているという意味でしかありません)。
RUNNABLEは"ready"と"running"の両方の状態に対応し、readyとrunningの両方の状態のスレッドはjava.lang.RUNNABLEで表されることを意味する。java.lang.RUNNABLE"で表現されます。
2. BLOCKED は "blocked" 状態に対応し、スレッドは実行を続けるためにロックを取得する必要があり、ロックは現在他のスレッドによって保持されているので、ロックを取得するまで受動待機状態となり、その後再び "ready" 状態となる。
3. 3. WAITINGはブロッキング状態に相当し、誰かがスレッドを起動するまで無期限に待機し、その後再びレディ状態になることを意味します。
4. TIMED_WAITING は "blocking" 状態に対応し、誰かがスレッドを起こすまで不定時間アクティブに待機するか、再びレディ状態になるまでに一定時間待機することを意味します。

II. コンストラクター

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }

   public Thread(String name) {
        init(null, null, name, 0);
    }

    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }


    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
     private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager what to do.
               what to do. */
            if (security ! = null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        g.checkAccess();

        if (security ! = null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc ! = null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals ! = null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inh

上記のコードから、Thread()は8つのコンストラクタを外部に提供していることがわかりますが、それらはすべて異なるパラメータを取った後、init(ThreadGroup g, Runnable target, String name, long stackSize) メソッドを呼び出しています。したがって、init()メソッドの解析は一度だけ行えばよいことになります。
init()メソッドには4つのパラメータがあり、表しています。

  1. ThreadGroup g は、現在のスレッドのスレッドグループを指定し、指定しない場合は、スレッドが作成されたスレッドグループを指定します。スレッドグループはスレッドのグループを管理するために使用することができ、 activeCount()はアクティブなスレッドの数を見るために使用することができます。それ以外に大きな使い道はありません。 
  2. Runnable targetは実行するRunnableを指定します。これは一般的に必須です。未指定のスレッドは意味がないか、Threadのサブクラスを作成してメソッドを再実行することで再実行できます。
  3. 文字列名 スレッドの名前。指定しない場合は自動生成される。
  4. long stackSize 予想されるスタックサイズ、デフォルトは指定がない場合0、0はこの属性を無視することを意味します。プラットフォーム依存のため、この属性は推奨されません。

iii. パブリックメソッド

Thread Thread.currentThread() : Get a reference to the current thread. After getting the current thread, operate on it.
Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() : Returns the default handler called when a thread abruptly terminates due to an uncaught exception.
int Thread.activeCount() : The number of active threads in the thread group of the current thread.
void dumpStack() : Print the current thread's stack trace to the standard error stream.
int enumerate(Thread[] tarray) : Copies each active thread in the thread group of the current thread and its subgroups to the specified array.
Map<Thread,StackTraceElement[]> getAllStackTraces() : Returns a map of the stack traces of all active threads.
boolean holdsLock(Object obj) : Returns true if and only if the current thread holds a monitor lock on the specified object.
boolean interrupted() : Test if the current thread has been interrupted.
void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) : Sets the default handler to be called when a thread terminates abruptly due to an uncaught exception and no other handler is defined for the thread.
void sleep(long millis) : sleep for a specified time
void sleep(long millis, int nanos) : hibernate for the specified time
void yield() : Suspends the currently executing thread object and executes another thread. Not very meaningful

void checkAccess() : Determine if the currently running thread has the right to modify the thread.
ClassLoader getContextClassLoader() : Returns the context ClassLoader of the thread.
long getId() : Returns the identifier of the thread.
String getName() : Returns the name of the thread.
int getPriority() : returns the priority of the thread.
StackTraceElement[] getStackTrace() : Returns an array of stack trace elements representing the stack dump of the thread.
Thread.State getState() : Returns the state of the thread.
ThreadGroup getThreadGroup() : Returns the thread group to which the thread belongs.
Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() : Returns the handler called when the thread terminates abruptly due to an uncaught exception.
void interrupt() : Interrupts the thread.
boolean isAlive() : Test if the thread is active.
boolean isDaemon() : Tests if the thread is a daemon.
boolean isInterrupted() : Tests if the thread has been interrupted.
void join() : Wait for the thread to terminate.
void join(long millis) : Wait for the thread to terminate for a maximum of millis milliseconds.
void join(long millis, int nanos) : Wait for the thread to terminate for a maximum of millis millis + nanos nanos.
void run() : Method to be executed after the thread is started.
void setContextClassLoader(ClassLoader cl) : Set the thread's context ClassLoader.
void setDaemon(boolean on) : Mark the thread as a daemon or user thread.
void start(): starts the thread; the Java virtual machine calls the run method of the thread.
String toString(): returns a string representation of the thread, including the thread name, priority, and thread group.

ここでは、Thread currentThread(), void run(), void start(), boolean interrupted(), void interrupt(), boolean isInterrupted(), void sleep(long millis) にフォーカスしています。
void join(long millis) , void join(long millis, int nanos) これらのメソッド
1. スレッド currentThread()
このメソッドは、現在のスレッドを取得し、スレッドオブジェクトを返すローカルスタティックメソッドです。

   public static native Thread currentThread();

2. void run()
は、スレッドがタスクを実行するためのメインコードです。

   public void run() {
        if (target ! = null) {
            target.run();
        }
    }

ターゲットが空でないときに、ターゲットの run メソッドを実行します。targetが空の場合は、このメソッドをオーバーライドする必要があり、このメソッドの内部にはビジネスロジックがある
3. void start()
Java仮想マシンは、スレッドのrunメソッドを呼び出します。

  public synchronized void start() {
        if (threadStatus ! = 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. if start0 threw a Throwable then
                  If start0 threw a Throwable then it will be passed up the call stack */
            }
        }
    }

    private native void start0();

4. boolean interrupted() & void interrupt() & boolean isInterrupted()
この3つのメソッドは、スレッド割り込みのためのものです マーカ メソッドを使用します。

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
     public boolean isInterrupted() {
        return isInterrupted(false);
    }
    public void interrupt() {
        if (this ! = Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b ! = null) {
                interrupt0(); // just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

    private native boolean isInterrupted(boolean ClearInterrupted);


interrupt():このスレッドに割り込む(割り込みの状態をtrueにする)
isInterrupted():スレッドが中断されたかどうかを検出します。中断された状態は、このメソッドの影響を受けません。割り込みが呼び出されたときにスレッドがアクティブでなくなっていた場合は、false が返されます。
interrupted():現在のスレッドが割り込まれたかどうかを検出します。現在のスレッドが割り込みフラグを持っている場合、true を返し、フラグを false に修正します。再度 isIterruoted() を呼び出すと false を返します。
テストコードです。

public class TestThread {
    public static void main(String[] args) throws Exception{
        test();
    }

    public static void test() throws Exception{
        Thread t1 = new Thread(new MyThread());
        Thread t2 = new Thread(new MyThread()). t2 = new Thread(new MyThread());
        t1.start();
        t1.interrupt();
        System.out.println("1"+t1.isInterrupted());
        System.out.println("2"+t1.isInterrupted());
        System.out.println("3"+t1.interrupted());
        t2.start();

    }

}

class MyThread extends Thread {

    @Override
    public void run() {

        for (int i = 0; i < 10000; i++) {

        }
        System.out.println("4"+currentThread().getName()+interrupted());
        System.out.println("5"+currentThread().getName()+interrupted());

    }
}

実装結果です。

1true
4Thread-1true
2false
5Thread-1false
3false
4Thread-3false
5Thread-3false

5. void sleep(long millis) & void sleep(long millis, int nanos)
この2つのメソッドは、スレッドをスリープさせるためのものです。

 public static void sleep(long millis, int nanos) throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException("nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos ! = 0 && millis == 0)) {
            millis++;
        }

        sleep(millis);
    }
   public static native void sleep(long millis) throws InterruptedException;

上記のように、2つの引数のsleepは、nanoをmillisに変換(丸め変換)してsleep(millis)メソッドを呼び出すだけです。
sleep(millis)は、現在のスレッドを指定された時間だけスリープさせるローカルメソッドです。
sleep はロックを解放しません。
6. void join() & void join(long millis) & void join(long millis, int nanos)
これら3つのメソッドは、スレッドの終了を待たせるためのものです。

    public final void join() throws InterruptedException {
        join(0);
    }
    public final synchronized void join(long millis, int nanos) throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos ! = 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }
   public final synchronized void join(long millis)throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

パラメータに0を渡すと、最後まで待つという意味になります。