Thread和Runnable深入源码剖析

一、Runnable的实现类

Thread类本质是Runnable的一个实现类,Runnable从jdk1.0就有了,并且在jdk1.8开始成为了一个函数式接口,这使得我么可以使用lambda简化线程的创建。

二、 Thread类的构造方法

所有构造方法都是调用init()方法来完成对一个线程的初始化,下面是init方法的jdk源码:

从源码中可以看出下面几点:

  • 每个线程都会有一个线程名,默认的名字是"Thread-" + nextThreadNum()
  • 每个新创建的线程的父线程就是当前线程;
  • 如果一个线程我们没有指定线程组,那么他会和父线程在同一线程组;
  • 如果父线程是守护线程,那么新创建的这个线程也是守护线程,反之同理;
  • 新创建的线程的优先级默认和父线程的优先级相同;

currentThread() ==>native方法,获取当前线程

默认线程名是"Thread"+nextThreadNum,线程名可以通过setName()方法修改,并且可以通过方法getName()方法获取到线程名

nextThreadNum()==>同步方法,维护了一个成员变量threadInitNumber,就是一个线程初始化的数字,没创建一个线程就+1

**设置线程名和获得线程名==>**setName() getName()

三、线程的优先级和线程状态

/**
*java中的线程优先级从1-10,默认是NORM_PRIORITY,优先级越高线程获得CPU时间片的概率就越大
*/
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

/**
*Java API提供的设置线程优先级的方法
*/
public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    // 优先级范围 1~10
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        // 设置优先级 native方法
        setPriority0(priority = newPriority);
    }
}

/**
*获得线程的优先级
*/
public final int getPriority() {
    return priority;
}
private native void setPriority0(int newPriority);



/**Thread内部类State 专门用来定义了线程的不同妆台,具体每个状态的含义就下面的注释,建议阅读英文注释
 * A thread state.  A thread can be in one of the following states:
 * NEW:A thread that has not yet started is in this state.
 * RUNNABLE:A thread executing in the Java virtual machine is in this state.
 * BLOCKED:A thread that is blocked waiting for a monitor lock is in this state.
 * WAITING:A thread that is waiting indefinitely for another thread to
 *         perform a particular action is in this state.
 * TIMED_WAITING:A thread that is waiting for another thread to perform an action
 *         for up to a specified waiting time is in this state.
 * TERMINATED:A thread that has exited is in this state.
 * A thread can be in only one state at a given point in time.
 * These states are virtual machine states which do not reflect
 * any operating system thread states.
 * @since   1.5
 */
public enum State {
    // 创建后,但是没有start(),调用了start()后,线程才算准备就绪,可以运行(RUNNABLE)
    NEW,
    // 正在运行或正在等待操作系统调度
    RUNNABLE,
    // 线程正在等待监视器锁
    // 正在synchronized块/方法上等待获取锁,或者调用了Object.wait(),等待重新获得锁进入同步块
    BLOCKED,
    // 调用Object.wait(),Thread.join()或LockSupport.park()会进入该状态,注意这里的调用均为没有设置超时,
    // 线程正在等待其他线程进行特定操作,比如,调用了Object.wait()的线程在另一个线程调用Object.notify()/Object.notifyAll()
    // 调用了Thread.join()的线程在等待指定线程停止,join()的内部实现方式也是Object.wait(),只不过其Object就是线程对象本身
    WAITING,
    // 调用Thread.sleep(),Object.wait(long),Thread.join(long),
    // LockSupport.parkNanos(long),LockSupport.parkUntil(long)会进入该状态,
    // 注意,这里的调用均设置了超时
    TIMED_WAITING,
    // 线程执行完成,退出
    TERMINATED;
}

/**
*jdk1.5开始提供的方法,用于获取线程的状态
*/
public State getState() {
    // get current thread state
    return sun.misc.VM.toThreadState(threadStatus);
}

注意一个线程在被从Object.wait()中被唤醒时,会立即进入BLOCKED状态,这时其并没有获得锁,只是被唤醒了,再次开始对Object的监视器锁进行竞争;只有在其竞争获得锁之后才会进入RUNNABLE状态.

四、run()和start()

run():如果是构造Thread对象的时候,传入了该对象预期执行的任务—-Runnable对象时,执行该任务,否则,什么都不做,当然,可以通过继承Thread类重写run()来修改其行为:

/* What will be run. */
private Runnable target;
@Override
public void run() {
    if (target != null) {

        target.run();
    }
}

start():以前面试最爱问的一个问题:调用start()与调用run()的区别?这还用说吗?调用run()只是普通的方法调动,执行的线程还是调用线程;而调用start()可以启动一个线程并是线程出入Runnable状态

/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
// 启动线程,JVM会调用当前Thread对象的run() 
// 同步方法
public synchronized void start() {
    // A zero status value corresponds to state "NEW".
    // 如果调用时不是在线程状态不是NEW,则抛出IllegalThreadStateException
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    /* Notify the group that this thread is about to be started
     * so that it can be added to the group's list of threads
     * and the group's unstarted count can be decremented. */
    group.add(this);
    boolean started = false;
    try {
    	// 通过native方法start0()来实现线程启动
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}


private native void start0();

通过上述start()方法的源码,可以总结出以下几个点:

  • (1) 当线程被构造完成之后,有个状态变量会记录线程的状态,就是上述的threadStatus,初始值在类中声明的为0;
  • (2) 调用start方法启动线程之后,threadStatus的值会被改变。如果再次重复调用start方法启动同一个线程时,会抛出IllegalThreadStateException异常;
  • (3) thread线程启动之后,会被加入到一个线程组ThreadGroup中;
  • (4) 线程如果启动失败了,线程组会对线程做失败处理,将其从线程组中移除;
  • (5) 如果一个线程生命周期结束了,再次调用start方法试图启动线程的时候,会提示IllegalThreadStateException异常,也就是处于TERMINATED状态的线程没办法重新回到RUNNABLE或者RUNNING状态;

下面是一个Java线程启动分析示意图

五、线程中断

/* The object in which this thread is blocked in an interruptible I/O
 * operation, if any.  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();

/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
 */
void blockedOn(Interruptible b) {
    synchronized (blockerLock) {
        blocker = b;
    }
}



public void interrupt(){
    if (this != Thread.currentThread())
        checkAccess();
    synchronized (blockerLock) {
        Interruptible b = blocker;
        // 在Interruptible上阻塞
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);      //Interruptible中的一个方法,两个实现类主要在nio包中
            return;
        }
    }
    interrupt0();
}
private native void interrupt0();


/**
*判断是否产生中断,两个方法:interrupted()  isInterrupted()
*/
public static boolean interrupted() {
    //清除中断标志位
    return currentThread().isInterrupted(true);
}

public boolean isInterrupted() {
    return isInterrupted(false);
}

/**
 * 返回线程是否被打断(打断标志是否被置位)
 * 传入的参数决定该方法是否会清除中断标志位
 */
private native boolean isInterrupted(boolean ClearInterrupted);

关于interrupt()方法的细节说明(以下是翻译自javadoc关于interrupt() 的说明):

  • (1)interrupt()的作用是中断本线程。本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。
  • (2)如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
  • (3)如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时,线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
  • (4)如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。
  • (5)中断一个“已终止的线程”不会产生任何操作。

另外关于isInterrupted()和interrupted()的区别,上述源码表现得很明显isInterrupted()在执行后不会清除中断标志位,interrupted()在方法执行后会清除中断标志位,而且是个静态方法。

六、线程礼让\睡眠\合并—yield() sleep() join()

/**
 * 暗示调度器让出当前线程的执行时间片,调度器可以选择忽略该暗示;
 * 该方法在用来调试和测试时可能很有用,可以用来重现需要特殊条件才能复现的bug;
 * 也可以用来进行并发优化等;
 */
public static native void yield();

/**
 * 当前执行线程休眠指定毫秒在休眠期间,不释放任何当前线程持有的锁;
 */
public static native void sleep(long millis) throws InterruptedException;

/**
 * 当前执行线程休眠指定毫秒在休眠期间,不释放任何当前线程持有的锁;
 * 如果当前被打断(该方法调用前或该方法调用时),抛出InterruptedException,同时将打断标志清掉
 */
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");
    }
    // 纳秒最后还是转换成了毫秒233333
    // 可能是考虑都有些
    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
        millis++;
    }
    sleep(millis);
}
/**
 * 当前执行线程等待指定线程(也就是该调用发生的Thread对象)死后再继续执行;
 * 可以设置超时,如果设置超时为0,则为不设置超时;
 * 线程结束时(terminate),将会调用自身的notifyAll(),唤醒在该Thread对象上wait()的方法;
 * 如果该线程被打断,该方法将抛出InterruptedException,并将打断标志位清除
 */
// 同步方法,同步当前Thread对象,所以才能在其内部调用wait()
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");
    }
    // 使用isAlive()和wait()的循环实现
    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

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 void join() throws InterruptedException {
    join(0);
}
/**
 * This method is called by the system to give a Thread
 * a chance to clean up before it actually exits.
 */
private void exit() {
    if (group != null) {
        group.threadTerminated(this);
        group = null;
    }
    /* Aggressively null out all reference fields: see bug 4006245 */
    target = null;
    /* Speed the release of some of these resources */
    threadLocals = null;
    inheritableThreadLocals = null;
    inheritedAccessControlContext = null;
    blocker = null;
    uncaughtExceptionHandler = null;
}

七、被遗弃的方法——suspend() resume() stop()

/**
 * 挂起当前线程
 * 弃用原因:容易导致死锁
 */
@Deprecated
public final void suspend() {
    checkAccess();
    suspend0();
}
/**
 * 从suspend()中恢复线程运行
 * 弃用原因:容易导致死锁
 */
@Deprecated
public final void resume() {
    checkAccess();
    resume0();
}
/**
 * 强制线程停止执行;
 * 通过抛出一个ThreadDeath的方式来停止线程;
 * 废弃原因:stop()会释放所有已持有的锁的监视器,如果存在之前被这些监视器保护的对象处于一个不连续
 * 的状态(inconsistent state),这些被损坏的对象将会对其他线程可见,出现不可预期的行为;
 */
@Deprecated
public final void stop() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        checkAccess();
        if (this != Thread.currentThread()) {
            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
        }
    }
    // A zero status value corresponds to "NEW", it can't change to
    // not-NEW because we hold the lock.
    if (threadStatus != 0) {
        resume(); // Wake up thread if it was suspended; no-op otherwise
    }
    // The VM can handle all thread states
    stop0(new ThreadDeath());
}

八、ThreadLocal: 在Thread中有两个关于ThreadLocal的成员变量

具体的ThreadLocal相关剖析请参考我的另一篇博客对ThreadLocal的理解?ThreadLocal如何解决内存泄漏问题?

/**
*每个线程的ThreadLocalMap
*/
ThreadLocal.ThreadLocalMap threadLocals = null;

/**
*  InheritableThreadLocal提供了一种父子线程之间的数据共享机制。
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

九、UncaughtExceptionHandler

// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;

// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

/**
 * 设置UncaughtExceptionHandler,该设置对所有线程有效
 * 如果自身没有设置,则交给其线程组的UncaughtExceptionHandler处理,如果再没有,
 * 则交给默认的的UncaughtExceptionHandler处理,也即这里设置的UncaughtExceptionHandler处理
 * 注意这里的设置不应该设置为线程的线程组,这样的设置会造成死循环
 */
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
    }
     defaultUncaughtExceptionHandler = eh;
 }
/**
 * 返回默认的UncaughtExceptionHandler,该UncaughtExceptionHandler对所有线程有效
 */
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
    return defaultUncaughtExceptionHandler;
}
/**
 * 返回该线程的UncaughtExceptionHandler,如果没有,返回该线程的线程组
 * ThreadGroup本身实现了UncaughtExceptionHandler接口
 */
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
    return uncaughtExceptionHandler != null ?
        uncaughtExceptionHandler : group;
}
/**
 * 设置该线程的UncaughtExceptionHandler
 */
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
    checkAccess();
    uncaughtExceptionHandler = eh;
}
/**
 * uncaught exception 分发给UncaughtExceptionHandler
 * 该方法被JVM调用
 */
private void dispatchUncaughtException(Throwable e) {
    getUncaughtExceptionHandler().uncaughtException(this, e);
}

留言区

还能输入500个字符