「源码学习」Thread 类

55 阅读5分钟

本想先了解多线程的源码,但是多线程的核心是线程嘛,那就先读读Thread的源码吧。

Runnable是一个函数式接口,它只有run()方法。可以重写run()方法,并将Runnable传递进Thread类,启动一个新线程执行Runnable中的run()方法。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

参数

    /**
     * 线程名称
     */
    private volatile char  name[];
    /**
     * 优先级
     */
    private int            priority;
    /**
     * 是否为守护线程
     */
    private boolean     daemon = false;
    /**
     * 线程要执行的目标任务
     */
    private Runnable target;
    /**
     * 线程组
     */
    private ThreadGroup group;
    /**
     * ThreadLocal为线程设置私有变量
     * ThreadLocal的get/set是通过调用各个线程的threadLocals变量实现的
     */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    /**
     * 线程栈的大小
     */
    private long stackSize;
    /**
     * 线程计数器
     */
    private static long threadSeqNumber;
    /**
     * 线程6个状态:New、Runnable、Blocked、Waiting、TimedWaiting、Terminated(终止)
     */
    private volatile int threadStatus = 0;


    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;

构造方法

    /**
     * 所有的构造器,都调用了init()方法,所以在new的时候,会进行一系列的初始化操作。
     */
    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);
    }

线程初始化

/**
     * Initializes a Thread with the current AccessControlContext.
     * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        //线程name不能为空
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name.toCharArray();
        //当前线程就是创建线程的父线程
        java.lang.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();
        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);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

线程状态操作

下面主要是改变线程状态的几个核心操作方法。

start

了解了start()源码,就自然知道平时启动线程为么调用start(),而不是run()。

public synchronized void start() {
        //如果当前线程初始化未做好,无法正常启动线程
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        //通知线程组,线程将要启动,线程组中未启动的线程数量减1
        group.add(this);

        boolean started = false;
        try {
            //调用native的start0()方法 启动线程,启动后执行run()方法
            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();
    
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

interrupt

终止线程推荐使用interrupt()方法,不要再使用过期的supend、resume、stop方法。因为这些方法挂起了也是会占用CPU资源。通信使用wait(),notify(),终止打断使用interrupt()。

       /**
	 * 终止线程。interrupt不会真正停止一个线程,它仅仅是给这个线程发了一个信号,
	 * 告诉它要结束了,具体要中断还是继续运行,将由被通知的线程自己处理
	 */
	public void interrupt() {
	    if (this != Thread.currentThread())
	        checkAccess();
	    synchronized (blockerLock) {
	        Interruptible b = blocker;
	        if (b != null) {
	            interrupt0();
	            b.interrupt(this);
	            return;
	        }
	    }
	    interrupt0();
	}

	private native void interrupt0();

join

join作用是让其他线程变为等待,该线程先执行。Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程(先执行指定的线程,再执行当前的线程)。比如在线程B(如主线程)中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

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

        /**
         * 如果这个线程还活着,就一直等待millis时间
         */
        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);
    }

sleep

使当前正在执行的线程进入睡眠状态,millis单位是毫秒。

       /**
	 * 线程睡眠指定的时间,释放CPU资源,但不释放锁
	 */
	public static native void sleep(long millis) throws 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");
        }

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

        sleep(millis);
    }

最后

在看Thread源码发现,最后调用都是native修饰的方法,简单科普下native。

  • 一个native方法就是一个Java调用非Java代码的接口。一个native方法是指该方法的实现由非Java语言实现,比如用C或C++实现。
  • 在定义一个native方法时,并不提供实现体(比较像定义一个Java Interface),因为其实现体是由非Java语言在外面实现的
  • JAVA无法对操作系统底层进行操作,但是可以通过jni(java native interface)调用其他语言来实现底层的访问。