JDK源码之Thread 类分析

一 概述

Thread类是java中的线程类,Java所有多线程的实现,均通过封装Thread类实现,Thread类实现了Runnable接口:

public class Thread implements Runnable {

二 Runnable接口

Runnable是一个函数式接口,接口里面只有一个run方法,用来执行线程运行的代码逻辑

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

三 ThreadGroup类

线程组是一个父子结构,一个线程组可以属于其他线程组,也可以拥有自己的子线程组,如果你一直向上追溯的话,会发现所有的线程组都在一个根线程组里面— System 线程组
线程组的出现可不是为耍酷用的,它是为了更方便的管理线程而存在的.比如设置线程最大优先级,销毁线程等等,添加线程,移除线程组等
还继承了Thread.UncaughtExceptionHandler,用来处理默认的线程异常捕获处理,如果线程没有设置处理器,默认走的是group的处理方法
其中大部分方法都是递归操作方法

    public class ThreadGroup implements Thread.UncaughtExceptionHandler {
        // 所属的父ThreadGroup
        private final ThreadGroup parent;
        // 线程组名称
        String name;
        // 最大优先级
        int maxPriority;
        /*是否被销毁*/
        boolean destroyed;
        // 是否是守护线程
        boolean daemon;
        //未启动线程数
        int nUnstartedThreads = 0;
        // 线程总数
        int nthreads;
        // 线程数组
        Thread threads[];
        // 线程组数量
        int ngroups;
        // 所拥有线程组数组
        ThreadGroup groups[];

        private ThreadGroup() {     // called from C code
            this.name = "system";
            this.maxPriority = Thread.MAX_PRIORITY;
            this.parent = null;
        }

        // 指定名字,父group为当前线程的线程组
        public ThreadGroup(String name) {
            this(Thread.currentThread().getThreadGroup(), name);
        }

        // 指定父group和name的线程组
        public ThreadGroup(ThreadGroup parent, String name) {
            this(checkParentAccess(parent), parent, name);
        }
      
    // 处理线程未检查异常异常,默认走这里,单独设置了走自己的
    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            // 获取默认的异常处理
            Thread.UncaughtExceptionHandler ueh =
                    Thread.getDefaultUncaughtExceptionHandler();
            // 如果有设置,则进行处理,否则直接打印System.err
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                        + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
        // 设置最大优先级,递归
        public final void setMaxPriority(int pri) {
            int ngroupsSnapshot;
            ThreadGroup[] groupsSnapshot;
            synchronized (this) {
                checkAccess();
                if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
                    return;
                }
                // 设置最大优先级不能超过 父group的最大优先级
                maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
                ngroupsSnapshot = ngroups;
                if (groups != null) {
                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
                } else {
                    groupsSnapshot = null;
                }
            }
            // 递归调用该线程组的每个线程组
            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
                groupsSnapshot[i].setMaxPriority(pri);
            }
        }

        // 递归获取线程总数
        public int activeCount() {
            int result;
            // Snapshot sub-group data so we don't hold this lock
            // while our children are computing.
            int ngroupsSnapshot;
            ThreadGroup[] groupsSnapshot;
            synchronized (this) {
                if (destroyed) {
                    return 0;
                }
                // 线程总数
                result = nthreads;
                ngroupsSnapshot = ngroups;
                if (groups != null) {
                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
                } else {
                    groupsSnapshot = null;
                }
            }
            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
                result += groupsSnapshot[i].activeCount();
            }
            return result;
        }

      .......add,remoev等其他方法

四 源码分析

属性

        // 线程名称
        private volatile String name;
        // 线程优先级
        private int priority;

        // 是否是守护线程,默认false
        private boolean daemon = false;

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

        // 要执行的任务
        private Runnable target;

        // 所属的线程群组
        private ThreadGroup group;

        // 每个线程实例都引用一个ThreadLocal的map,每个线程在向ThreadLocal里塞值的时候,其实都是向自己所持有的ThreadLocalMap里塞入数据
       // 读数据同理,根据ThreadLocal引用作为key取出value,实现线程隔离
        ThreadLocal.ThreadLocalMap threadLocals = null;

        /*
           * InheritableThreadLocal,自父线程集成而来的ThreadLocalMap,
           * 主要用于父子线程间ThreadLocal变量的传递,实现类是InheritableThreadLocal类
       */
       ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

        /* 用于自动编号匿名线程 */
        private static int threadInitNumber;
        // 同步方法,编号唯一
        private static synchronized int nextThreadNum() { return threadInitNumber++;  }

        // 线程栈大小
        private long stackSize;

        // 线程ID
        private long tid;

        // 用于生成线程ID的序列号
        private static long threadSeqNumber;

        private volatile int threadStatus = 0;

        // 获取下一个线程ID,同步
        private static synchronized long nextThreadID() {  return ++threadSeqNumber;   }

        // 线程最低优先级
        public final static int MIN_PRIORITY = 1;

        // 线程默认分配的优先级
        public final static int NORM_PRIORITY = 5;

        // 线程最高优先级
        public final static int MAX_PRIORITY = 10;

构造器

        // 线程无法克隆
        @Override
        protected Object clone() throws CloneNotSupportedException {
            throw new CloneNotSupportedException();
        }

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

        // 线程初始化
        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) {
            // 线程名字不能为null
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
            this.name = name;
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            // 每个线程都必须在一个线程组中,如果g为null,则设置为当前线程或者SecurityManager的线程组
            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;
            // 设置优先级与是否是守护线程,与ThreadGroup相同
            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);
           // 如果父线程的inheritableThreadLocals不为null,则将父线程inheritableThreadLocals传递至子线程
           // 实现类是InheritableThreadLocal,
            if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                      // 调用ThreadLocal的createInheritedMap方法,复制父线程table到当前线程的inheritableThreadLocals
                      this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            // 设置指定的栈大小,如果未指定大小,将在jvm 初始化参数中声明:Xss参数进行指定
            this.stackSize = stackSize;
            // 设置线程ID
            tid = nextThreadID();
        }

        // 设置优先级
        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);
            }
        }
        // 设置线程优先级
        private native void setPriority0(int newPriority);

        // 构造器,所有构造器都调用init方法,每个线程都有所属的线程组
        public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }

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

核心方法

interrupt

        /**
         * 中断线程,设置中断标志位(并不会立即停止线程):
         *
         * 1 如果当前线程阻塞在Object.wait(),Thread.join(),Thread.sleep()上,那么该线程会收到InterruptedException,且线程的打断标志会被清除;
         * 2 如果当前线程阻塞在InterruptibleChannel上,那么该InterruptibleChannel会被关闭,线程的打断标志会被置位,且当前线程会收到ClosedByInterruptException;
         * 3 如果当前线程阻塞在Selector上,那么该Selector的selection操作将会立即返回一个非0的结果,且Selector.wakeup()会被调用,线程的打断标志会被置位,
         * 4 如果上述情况均不存在,将当前线程的打断标志置位,并不会马上停止线程
         * 5 打断一个isAlive()返回false的线程没有效果,isInterrupted()仍然会返回false;
         */
        public void interrupt() {
            if (this != Thread.currentThread())
                checkAccess();

            synchronized (blockerLock) {
                // Interruptible 是一个只有interrupt方法的接口
                Interruptible b = blocker;
                // 在Interruptible上阻塞
                if (b != null) {
                    // 只是设置中断标志,并没有停止线程
                    interrupt0();
                    b.interrupt(this);
                    return;
                }
            }
            interrupt0();
        }
        private native void interrupt0();

        // 判断当前线程是否中断,传入true,会清除中断标志位,即重新置为false(默认是false)
        public static boolean interrupted() {
            return currentThread().isInterrupted(true);
        }

        //判断线程是否终端  传入false,不会清除中断标志位
        public boolean isInterrupted() {
            return isInterrupted(false);
        }
        /**
         * 返回线程是否被打断(打断标志是否被置位)
         * 传入的参数决定是否该方法是否会清除终端标志位
         */
        private native boolean isInterrupted(boolean ClearInterrupted);

start 与 run

        // strat 同步方法,启动线程
        public synchronized void start() {
            // 如果调用时不是在线程状态不是NEW,则抛出IllegalThreadStateException, 0 表示NEW状态
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
            // 将当前线程加入所属线程组数组,并维护线程总数(+1)和未启动数量(-1)
            group.add(this);
            boolean started = false;
            try {
                // 启动线程
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        // 启动失败,会移除线程组并还原未启动数量+1
                        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();

        // 执行runable的run方法
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }

setName

        // 线程名称可以修改
        public final synchronized void setName(String name) {
            checkAccess();
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }

            this.name = name;
            if (threadStatus != 0) {
                setNativeName(name);
            }
        }

        public final String getName() {
            return name;
        }

sleep与join

        /**
         * 当前执行线程休眠指定毫秒在休眠期间,不释放任何当前线程持有的锁;
         */
        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;


        /**
         * 当前执行线程等待指定线程(也就是该调用发生的Thread对象)死后再继续执行;
         * 可以设置超时,如果设置超时为0,则为不设置超时;
         * 线程结束时(terminate),将会调用自身的notifyAll(),唤醒在该Thread对象上wait()的方法;
         * 如果该线程被打断,该方法将抛出InterruptedException,并将打断标志位清除
         */
        public final void join() throws InterruptedException {
            join(0);
        }

        // 返回当前线程是否还活着
        // start()后且还没有死亡的线程均视为活着的线程
        public final native boolean isAlive();

        // 同步方法,需要锁
        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循环方式来检查条件
                while (isAlive()) {
                    // wait会释放锁,其他线程就可以调用join,
                    // 当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列
                    // 比如主线程里调用了线程A的wait(进入join会获取锁,join是同步方法),主线程就会释放锁,并进入这个对象的等待队列,等待notify通知之后才能继续运行,notify等代码写在本地实现里面
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }

线程轨迹

        // 静态方法,打印当前线程的栈轨迹(StackTrace),通过新建一个异常的方式实现
        public static void dumpStack() {
            new Exception("Stack trace").printStackTrace();
        }

        private static final StackTraceElement[] EMPTY_STACK_TRACE
                = new StackTraceElement[0];

        /**
         * 获得栈轨迹,返回的是一个数组
         * 数组的第0个栈轨迹为最近调用的栈轨迹
         */
        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);
                }
                // 线程死亡,返回空
                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();
            }
        }

        // 返回所有线程的栈轨迹
        public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
            // check for getStackTrace permission
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkPermission(
                        SecurityConstants.GET_STACK_TRACE_PERMISSION);
                security.checkPermission(
                        SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
            }

            // 获取所有线程列表的快照
            Thread[] threads = getThreads();
            StackTraceElement[][] traces = dumpThreads(threads);
            Map<java.lang.Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
            for (int i = 0; i < threads.length; i++) {
                StackTraceElement[] stackTrace = traces[i];
                if (stackTrace != null) {
                    m.put(threads[i], stackTrace);
                }
                // else terminated so we don't put it in the map
            }
            return m;
        }

        private native static StackTraceElement[][] dumpThreads(Thread[] threads);
        private native static Thread[] getThreads();

使用:

    public static void main(String[] args) throws InterruptedException {
        // 获取所有线程轨迹,key线程,value轨迹map,即执行方法倒序,最后执行方法的在最前面
        Thread.getAllStackTraces().forEach((key, value) -> {
            System.out.println(key);
            System.out.println(Arrays.toString(value));
        });
        // 获取当前线程轨迹
        System.out.println("-----------------");
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        System.out.println(Arrays.toString(stackTrace));
    }

查看打印:

UncaughtExceptionHandler

        // 对于未检查异常,如果在run()方法中运行出现了未检查异常,那么默认的行为是将堆栈跟踪信息写到控制台中(或者记录到错误日志文件中),然后退出程序
        // 此函数式接口,用来捕获并处理在一个线程对象中抛出的未检查异常,以避免线程终止
        @FunctionalInterface
        public interface UncaughtExceptionHandler {
            void uncaughtException(Thread t, Throwable e);
        }

        // null unless explicitly set
        private volatile Thread.UncaughtExceptionHandler uncaughtExceptionHandler;

        // 所有线程共享默认的,如果线程不设置,默认取这个,如果等于null,直接程序终止,不等于处理逻辑
        private static volatile Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
        //..... 两个属性 get,set
        private void dispatchUncaughtException(Throwable e) {
            getUncaughtExceptionHandler().uncaughtException(this, e);
        }

使用,可以直接捕获到线程中的异常

    public static void main(String[] args) throws InterruptedException {
        // 设置所有线程
        // Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

        Thread thread = new Thread(() -> {
            System.out.println("程序start");
            //每个线程单独设置,如果没有,默认获取所有默认的
            Thread.currentThread().setUncaughtExceptionHandler((x, y) -> {
                System.out.println(x.getName());
                System.out.println(y.getMessage());
            });
            // 这种就是未检查异常,并没有trycatch,是代码逻辑问题,直接抛异常会导致程序结束
            Integer.parseInt("h哈哈");
        });
        thread.start();
        Thread.sleep(1000);
        System.out.println("程序继续111");
    }

捕捉:

四 总结

常见面试题

posted @ 2020-02-07 16:17  侯小厨  阅读(546)  评论(0编辑  收藏  举报
Fork me on Gitee