zoukankan      html  css  js  c++  java
  • Thread类源码解析

    源码版本:jdk8

    其中的部分论证和示例代码:Java_Concurrency


    类声明:

    Thread本身实现了Runnable接口

    Runnable:任务,《java编程思想》中表示该命名不好,或许叫Task更好;

    Thread:线程,执行任务的载体;

    public class Thread implements Runnable 
    

    **构造方法: **

    构造时,可以指定线程组,线程运行任务Runnable对象,线程名和栈大小

    线程的所有构造方法,都是通过init()实现

    /**
     * Thread的所有public构造方法传入的inheritThreadLocals均为true
     * 只有一个权限为default的构造方法传入为false
     * 所有的构造方法实现均是调用了该方法
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
    	// 构造方法中传入的线程名不能为null
    	// 默认线程名:"Thread-" + nextThreadNum()
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name;
    	// 被创建出来的线程是创建线程的子线程
        Thread parent = currentThread();
    	// 新建线程的线程组
    	// 如果构造方法传入的线程组为null,则通过这个流程来决定其线程组,通常,新建线程的线程组为其创建线程的线程组
        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. */
            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();
            }
        }
        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();
        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        g.addUnstarted();
        this.group = g;
    	// 子线程默认拥有父线程的优先级和daemon属性
        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.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;
    	// 产生新的tid并设置
        tid = nextThreadID();
    }
    public long getId() {
    	return tid;
    }
    

    上面的源码中有一个stackSize的参数,这个一般不会使用,其具体请参考javadoc.

    默认线程名:"Thread-" + nextThreadNum():

    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    // 同步方法,保证tid的唯一性和连续性
    private static synchronized int nextThreadNum() {
    	return threadInitNumber++;
    }
    // 线程名可以被修改
    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;
    }
    

    ThreadGroup:

    《java编程思想》有云:把ThreadGroup当做是一次不成功的尝试即可,不用理会

    示例:ThreadGroupTest.java

    public final ThreadGroup getThreadGroup() {
    	return group;
    }
    

    Thread类默认的toString()中有使用其ThreadGroup:

    public String toString() {
        ThreadGroup group = getThreadGroup();
        if (group != null) {
            return "Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]";
        } else {
            return "Thread[" + getName() + "," + getPriority() + "," + "" + "]";
        }
    }
    

    守护线程:

    具体参考:Java 守护线程概述

    示例:Daemon.java

    /**
     * Marks this thread as either a {@linkplain #isDaemon daemon} thread
     * or a user thread. The Java Virtual Machine exits when the only
     * threads running are all daemon threads.
     * <p> This method must be invoked before the thread is started.
      */
    public final void setDaemon(boolean on) {
        checkAccess();
        // 只有在线程开始前设置才有效
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }
    public final boolean isDaemon() {
    	return daemon;
    }
    
    // 返回当前线程是否还活着
    // start()后且还没有死亡的线程均视为活着的线程
    public final native boolean isAlive();
    

    线程优先级和线程状态:

    Java 线程状态与优先级相关的知识题目

    示例:ThreadState.java

    Priority.java

    构造时如果不指定,默认线程优先级就是NORM_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();
        // 优先级范围 1~10
        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;
    }
    private native void setPriority0(int newPriority);
    /**
     * 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;
    }
    // @since 1.5
    public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }
    

    这里关于线程状态需要特别注意,在网上有很多博客和书籍对线程状态进行讲解,其中很大一部分是错误的,对于BLOCKED,WAITING和TIMED_WAITING有所误解,认为一个线程在被从Object.wait()中被唤醒时,会立即进入Runnable状态,其实不是的:

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

    在理解java线程状态时,建议直接看Thread.State的注释,就看英文版本,最贴切,没有杂质,也最正确,其他的所有书上的讲解似乎都有些偏颇

    线程状态示例:ThreadState.java

    线程优先级示例:Priority.java

    关于wait()/notify()具体相关,请参考其他相关博客;

    run():

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

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

    线程启动:

    调用start()与调用run()的区别:懒得说

    /* 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 {
        	// 通过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();
    

    线程打断:

    示例:Interrupted.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;
        }
    }
    /**
     * 打断当前执行线程
     * 如果当前线程阻塞在Object.wait(),Thread.join(),Thread.sleep()上,
     * 那么该线程会收到InterruptedException,且线程的打断标志会被清除;
     * 如果当前线程阻塞在InterruptibleChannel上,那么该InterruptibleChannel
     * 会被关闭,线程的打断标志会被置位,且当前线程会收到ClosedByInterruptException;
     * 如果当前线程阻塞在Selector上,那么该Selector的selection操作将会立即返回一个非0的结果,
     * 且Selector.wakeup()会被调用,线程的打断标志会被置位,
     * 如果上述情况均不存在,将当前线程的打断标志置位
     * 打断一个isAlive()返回false的线程没有效果,isInterrupted()仍然会返回false;
     */
    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);
                return;
            }
        }
        interrupt0();
    }
    private native void interrupt0();
    
    /**
     * 返回线程是否被打断(打断标志是否被置位)
     * 传入的参数决定是否该方法是否会清除终端标志位
     */
    private native boolean isInterrupted(boolean ClearInterrupted);
    
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    

    关于isInterrupted()和interrupted()的区别,上述源码表现得很明显

    而且,也体现了NIO的可中断中断实现方式

    注意:interrupt()不能中断执行阻塞IO操作的线程.

    线程的礼让—— yield() sleep() join():

    关于Thread.sleep()和Object.wait()的区别:参考链接

    示例:Yield.java

    Join.java

    /**
     * 暗示调度器让出当前线程的执行时间片,调度器可以选择忽略该暗示;
     * 该方法在用来调试和测试时可能很有用,可以用来重现需要特殊条件才能复现的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.java

    关于这些方法被遗弃的原因,具体参考:Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?

    /**
     * 挂起当前线程
     * 弃用原因:容易导致死锁
     */
    @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源码解读

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

    ClassLoader:

    关于ClassLoader,我暂时知道的也不多,先知道这个,以后有机会专门研究一下ClassLoader:

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;
    /**
     * 当前线程的ClassLoader,默认创建时是父线程的ClassLoader
     * @return  the context ClassLoader for this Thread, or {@code null}
     *          indicating the system class loader (or, failing that, the
     *          bootstrap class loader)
     * @since 1.2
     */
    @CallerSensitive
    public ClassLoader getContextClassLoader() {
        if (contextClassLoader == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader.checkClassLoaderPermission(contextClassLoader,Reflection.getCallerClass());
        }
        return contextClassLoader;
    }
    /**
     * @param  cl
     *         the context ClassLoader for this Thread, or null  indicating the
     *         system class loader (or, failing that, the bootstrap class loader)
     * @since 1.2
     */
    public void setContextClassLoader(ClassLoader cl) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
        }
        contextClassLoader = cl;
    }
    

    线程栈轨迹:

    // 特殊编程技巧
    private static final StackTraceElement[] EMPTY_STACK_TRACE
            = new StackTraceElement[0];
    private native static StackTraceElement[][] dumpThreads(Thread[] threads);
    private native static Thread[] getThreads();
    
    // 打印当前线程的栈轨迹(StackTrace),通过新建一个异常的方式实现
    // 注意:这是一个静态方法
    public static void dumpStack() {
        new Exception("Stack trace").printStackTrace();
    }
    /**
     * 获得栈轨迹,返回的是一个数组
     * 数组的第0个栈轨迹为最近调用的栈轨迹
     * @since 1.5
     */
    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);
            }
            // 不是活着的,返回的栈轨迹长度为0
            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) {
            	// 这样就不会返回null,调用者也无需判断null了
                stackTrace = EMPTY_STACK_TRACE;
            }
            return stackTrace;
        } else {
            // Don't need JVM help for current thread
            return (new Exception()).getStackTrace();
        }
    }
    /**
     * 返回所有线程的栈轨迹
     * @since 1.5
     */
    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);
        }
    
        // Get a snapshot of the list of all threads
        Thread[] threads = getThreads();
        StackTraceElement[][] traces = dumpThreads(threads);
        Map<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;
    }
    

    UncaughtExceptionHandler:

    示例:UncaughtExceptionHandlerEx.java

    // null unless explicitly set
    private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
    // null unless explicitly set
    private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
    /**
     * 设置UncaughtExceptionHandler,该设置对所有线程有效
     * 如果自身没有设置,则交给其线程组的UncaughtExceptionHandler处理,如果再没有,
     * 则交给默认的的UncaughtExceptionHandler处理,也即这里设置的UncaughtExceptionHandler处理
     * 注意这里的设置不应该设置为线程的线程组,这样的设置会造成死循环
     * @since 1.5
     */
    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
        }
         defaultUncaughtExceptionHandler = eh;
     }
    /**
     * 返回默认的UncaughtExceptionHandler,该UncaughtExceptionHandler对所有线程有效
     * 这是一个静态方法
     * @since 1.5
     */
    public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
        return defaultUncaughtExceptionHandler;
    }
    /**
     * 返回该线程的UncaughtExceptionHandler,如果没有,返回该线程的线程组
     * ThreadGroup本身实现了UncaughtExceptionHandler接口
     * @since 1.5
     */
    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);
    }
    

    其他:

    // 返回当前语句执行的线程
    public static native Thread currentThread();
    // 不能克隆线程
    @Override
    protected Object clone() throws CloneNotSupportedException {
    	throw new CloneNotSupportedException();
    }
    /**
     * 返回该线程是否持有指定对象的监视器锁
     * @since 1.4
     */
    public static native boolean holdsLock(Object obj);
    
  • 相关阅读:
    Myeclipse下使用Maven搭建spring boot项目
    Dubbo+Zookeeper视频教程
    dubbo项目实战代码展示
    流程开发Activiti 与SpringMVC整合实例
    交换两个变量的值,不使用第三个变量的四种法方
    数据库主从一致性架构优化4种方法
    数据库读写分离(aop方式完整实现)
    在本地模拟搭建zookeeper集群环境实例
    box-sizing布局
    盒子模型
  • 原文地址:https://www.cnblogs.com/jamesvoid/p/10011694.html
Copyright © 2011-2022 走看看