Thread源码分析

基于jdk1.8进行分析的。

继承结构

public
class Thread implements Runnable

可见实现了Runnable接口,那么我们顺便看一下Runnable接口的源码。

public interface Runnable {
    public abstract void run();
}

由此联想到是不是Thread重写了run方法呢?我们在此看一下。

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

可见真的是这样,但是调用的是target的run方法执行的。此处后面再说。

源码往下看首先看到的是:

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

由此看到的是一个静态代码块,以及一个调用一个本地的方法,因为看到了关键字native。registerNatives方法因此可能是由C/C++实现的dll文件,然后执行的时候通过Java代码进行调用。

成员属性

    //线程名字
    private volatile char  name[];
    //优先级
    private int            priority;
    private Thread         threadQ;
    private long           eetop;
    //是否是单步执行
    private boolean     single_step;
    //是否是守护线程
    private boolean     daemon = false;
    // 虚拟机状态
    private boolean     stillborn = false;
    //将会被执行的Runnable.
    private Runnable target;
    //这个线程的组
    private ThreadGroup group;
    //这个线程的上下文
    private ClassLoader contextClassLoader;
    //继承的请求控制
    private AccessControlContext inheritedAccessControlContext;
    //默认线程的自动编号
    private static int threadInitNumber;
    //当前线程附属的ThreadLocal,而ThreadLocalMap会被ThreadLocal维护)
    ThreadLocal.ThreadLocalMap threadLocals = null;
    //主要作用:为子线程提供从父线程那里继承的值
    //在创建子线程时,子线程会接收所有可继承的线程局部变量的初始值,以获得父线程所具有的值
    //创建一个线程时如果保存了所有 InheritableThreadLocal 
    //对象的值,那么这些值也将自动传递给子线程
    //如果一个子线程调用 InheritableThreadLocal 的 get() ,那么它将与它的父线程看到同一个对象
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    //该线程请求的堆栈大小 默认一般都是忽略
    private long stackSize;
    private long nativeParkEventPointer;
    // 每个线程都有专属ID,但名字可能重复
    private long tid;
    //用来生成thread ID
    private static long threadSeqNumber;
    //标识线程状态,默认是线程未启动
    private volatile int threadStatus = 0;
    //中断阻塞器:当线程发生IO中断时,需要在线程被设置为中断状态后调用该对象的interrupt方法
    volatile Object parkBlocker;
    //阻塞器锁,主要用于处理阻塞情况
    private volatile Interruptible blocker;
    //阻断锁
    private Object blockerLock = new Object();
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
    //线程的优先级中最小的
    public final static int MIN_PRIORITY = 1;
    //线程的优先级中第二的同时也是默认的优先级
    public final static int NORM_PRIORITY = 5;
    //最高的优先级
    public final static int MAX_PRIORITY = 10;
    //判断stop是否在Start前
    private boolean stopBeforeStart;
    private Throwable throwableFromStop;

以上大致是关于Thread类的所有的成员属性的注释,此处不再一一赘述。

构造方法

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc);
    }
    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);
    }

可以看到有九个构造方法,通过源码可以看到都是通过调用init方法进行初始化的。稍后粘贴源码。

native方法

    //获得当前的线程
    public static native Thread currentThread();
    //使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。
    //cpu会从众多的可执行态里选择,也就是说,
    //当前也就是刚刚的那个线程还是有可能会被再次执行到的,
    //并不是说一定会执行其他线程而该线程在下一次中不会执行到了
    public static native void yield();
    //静态方法强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。 
    //当线程睡眠时,它睡在某个地方,在苏醒之前不会返回到可运行状态。 
    //当睡眠时间到期,则返回到可运行状态。
    public static native void sleep(long millis) throws InterruptedException;
    //开始线程
    private native void start0();
    //设置线程优先级
    private native void setPriority0(int newPriority);
    //停止线程
    private native void stop0(Object o);
    // 线程挂起(暂停)
    private native void suspend0();
    //将一个挂起线程复活继续执行
    private native void resume0();
    //该线程的中断状态将被设置
    private native void interrupt0();
    //判断线程是否存活
    public final native boolean isAlive();
    //当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
    public static native boolean holdsLock(Object obj);

其他成员方法

首先看一下init方法的实现。

init(ThreadGroup g, Runnable target, String name,long stackSize)

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }

可以看到通过调用init方法实现,那么往下看。

    //这是线程初始化方法
    //g是线程组
    //target被调用RUN方法的目标对象
    //name新线程的名字
    //stackSize用于新线程分配所需堆栈大小
    //最后一个参数可以看到在Thread中实现的时候,大部分构造参数传入的是null,
    //所以在此不予以详细讨论,如果想指定,那么可以通过构造方法传入。
    private void init(ThreadGroup g,
                        Runnable target, 
                        String name,
                        long stackSize, 
                        AccessControlContext acc) {//最后一个参数是控制安全方面的
        //名字为空,直接空指针异常
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        //默认传入的name"Thread-" + nextThreadNum()
        this.name = name.toCharArray();
        //获得当前线程                 
        Thread parent = currentThread();
        //获得系统的安全管理器
        SecurityManager security = System.getSecurityManager();
        //如果没有指定线程组
        if (g == null) {
            //安全检查
            if (security != null) {
                g = security.getThreadGroup();
            }
            //设置线程组
            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();
        //每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。
        //每个线程都可以或不可以标记为一个守护程序。
        //当某个线程中运行的代码创建一个新 Thread 对象时,
        //该新线程的初始优先级被设定为创建线程的优先级,
        //并且当且仅当创建线程是守护线程时,新线程才是守护程序。
        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 (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        //该线程请求的堆栈大小 
        this.stackSize = stackSize;
        //每个线程都有专属ID
        tid = nextThreadID();
    }

 sleep(long millis, int nanos) 

    //可以设置
    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);
    }

方法对传入的nanos进行了判断 

  • 1.也就是当nanos大于等于500微秒时,millis就加1.当nanos小于500微秒时,不改变millis的值。
  • 2.当millis的值为0时,只要nanos不为0,就将millis设置为1。

start()

    //使线程进入可执行(runnable状态)的状态
    public synchronized void start() {
        //验证线程的状态,如果线程已启动则抛异常 
        //可以防止某一个线程被调用多次
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        //向线程组里添加此线程
        group.add(this);
        boolean started = false;
        try {
            //使线程进入可执行(runnable状态)的状态
            start0();
            //线程启动成功
            started = true;
        } finally {
            try {
                //线程没有被成功启动
                if (!started) {//下面的方法是将该线程从线程组中移除,并将未启动线程参数+1
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }

关于start方法怎么最终调用到实现重写的run方法,是通过调用本地方法实现的,具体实现细节,不在此处赘述,感兴趣的朋友,可以自己去查一下。

exit()

在run()方法执行结束后用于结束线程的。通过单步调试一个线程发现执行完run方法之后会进入exit方法。

    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;
    }

stop()

通过注解可以看到该方法已经不建议使用了。 

    @Deprecated
    public final void stop() {
        //安全管理器
        SecurityManager security = System.getSecurityManager();
        //如果没有定义
        if (security != null) {
            //检查是否允许调用线程修改线程组参数
            checkAccess();
            //如果这个线程不是当前线程
            if (this != Thread.currentThread()) {
                //如果所请求的访问,通过给定的权限,
                //指定的安全策略不允许根据当前有效的方法将抛出一个SecurityException。
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        //如果线程已启动
        if (threadStatus != 0) {
            resume(); //线程继续执行
        }

        //停止线程
        stop0(new ThreadDeath());
    }

suspend() 

挂起线程,可见已经也不建议使用 

    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }

resume()

线程从挂起到唤醒,也已经不建议使用 

    @Deprecated
    public final void resume() {
        checkAccess();
        resume0();
    }

setPriority(int newPriority)

设置线程的优先级 

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

 getPriority()

获取线程优先级 

    public final int getPriority() {
        return priority;
    }

enumerate(Thread tarray[])

将这个线程组中存活的线程全部复制到预设置好的数组中 

    public static int enumerate(Thread tarray[]) {
        return currentThread().getThreadGroup().enumerate(tarray);
    }

activeCount()

获得当前线程组中还在活动中的线程数 

    public static int activeCount() {
        return currentThread().getThreadGroup().activeCount();
    }

join(long millis)

堵塞当前线程,使其处于等待状态,因为子线程执行的时间可能比主线程执行时间还长,所以join是主线程需要在它执行完后再销毁。当然也可以加参数join(long millis, int nanos),使其等待N秒N毫秒,如果它已经处于join方法,则报InterruptedException。

    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");
        }
        //如果当前线程存活,那么释放锁,进入wait状态,另外可以看到是由synchronized标识的
        if (millis == 0) {
            while (isAlive()) {
                //释放锁,进入wait状态
                wait(0);
            }
        } else {//millis>0情况的处理
            while (isAlive()) {//当前线程存活
                long delay = millis - now;//推迟时间计算
                if (delay <= 0) {//数据合法性处理
                    break;
                }
                //释放锁,进入等待状态
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

join(long millis, int nanos)

此处不再赘述,可见最后是通过调用join方法实现的。 

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

join()

通过源码可以看到也是通过join(long millis)方法实现的 

    public final void join() throws InterruptedException {
        join(0);
    }

现在是停在这里,下面继续。

dumpStack()

将当前线程的堆栈跟踪打印至标准错误流

    public static void dumpStack() {
        new Exception("Stack trace").printStackTrace();
    }

setDaemon(boolean on)

设置线程是否是守护线程 

    public final void setDaemon(boolean on) {
        //检查是否允许调用线程修改线程组参数
        checkAccess();
        //首先先去确认此线程是否处于活动状态,如果处于活动状态则抛异常
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        //将其设置为守护线程
        daemon = on;
    }

checkAccess() 

检查是否允许调用线程修改线程组参数 

    public final void checkAccess() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkAccess(this);
        }
    }

 getContextClassLoader()

返回该线程的上下文 ClassLoader。上下文 ClassLoader 由线程创建者提供,供运行于该线程中的代码在加载类和资源时使用。如果未设定,则默认为父线程的 ClassLoader 上下文。原始线程的上下文 ClassLoader 通常设定为用于加载应用程序的类加载器。首先,如果有安全管理器,并且调用者的类加载器不是 null,也不同于其上下文类加载器正在被请求的线程上下文类加载器的祖先,则通过 RuntimePermission("getClassLoader") 权限调用该安全管理器的 checkPermission 方法,查看是否可以获取上下文 ClassLoader。

    @CallerSensitive
    public ClassLoader getContextClassLoader() {
        if (contextClassLoader == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                                   Reflection.getCallerClass());
        }
        return contextClassLoader;
    }

getStackTrace()

返回一个表示该线程堆栈转储的堆栈跟踪元素数组。可以看到是通过Exception类的getStackTrace实现的。有对这部分感兴趣的朋友,可以自己查一下关于这个方法。 

    public StackTraceElement[] getStackTrace() {
        if (this != Thread.currentThread()) {
            // check for getStackTrace permission
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkPermission(
                    SecurityConstants.GET_STACK_TRACE_PERMISSION);
            }
            // optimization so we do not call into the vm for threads that
            // have not yet started or have terminated
            if (!isAlive()) {
                return EMPTY_STACK_TRACE;
            }
            StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
            StackTraceElement[] stackTrace = stackTraceArray[0];
            // a thread that was alive during the previous isAlive call may have
            // since terminated, therefore not having a stacktrace.
            if (stackTrace == null) {
                stackTrace = EMPTY_STACK_TRACE;
            }
            return stackTrace;
        } else {
            // Don't need JVM help for current thread
            return (new Exception()).getStackTrace();
        }
    }

到此整个Thread源码已经分析差不多了。如果有问题,或者分析不对的地方,欢迎留言指征。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值