本想先了解多线程的源码,但是多线程的核心是线程嘛,那就先读读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)调用其他语言来实现底层的访问。