一、Runnable的实现类
Thread类本质是Runnable的一个实现类,Runnable从jdk1.0就有了,并且在jdk1.8开始成为了一个函数式接口,这使得我么可以使用lambda简化线程的创建。
二、 Thread类的构造方法
所有构造方法都是调用init()方法来完成对一个线程的初始化,下面是init方法的jdk源码:
从源码中可以看出下面几点:
- 每个线程都会有一个线程名,默认的名字是
"Thread-" + nextThreadNum()
; - 每个新创建的线程的父线程就是当前线程;
- 如果一个线程我们没有指定线程组,那么他会和父线程在同一线程组;
- 如果父线程是守护线程,那么新创建的这个线程也是守护线程,反之同理;
- 新创建的线程的优先级默认和父线程的优先级相同;
currentThread() ==>native方法,获取当前线程
默认线程名是"Thread"+nextThreadNum,线程名可以通过setName()方法修改,并且可以通过方法getName()方法获取到线程名
nextThreadNum()==>同步方法,维护了一个成员变量threadInitNumber,就是一个线程初始化的数字,没创建一个线程就+1
**设置线程名和获得线程名==>**setName() getName()
三、线程的优先级和线程状态
/**
*java中的线程优先级从1-10,默认是NORM_PRIORITY,优先级越高线程获得CPU时间片的概率就越大
*/
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
/**
*Java API提供的设置线程优先级的方法
*/
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();
}
// 设置优先级 native方法
setPriority0(priority = newPriority);
}
}
/**
*获得线程的优先级
*/
public final int getPriority() {
return priority;
}
private native void setPriority0(int newPriority);
/**Thread内部类State 专门用来定义了线程的不同妆台,具体每个状态的含义就下面的注释,建议阅读英文注释
* 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;
}
/**
*jdk1.5开始提供的方法,用于获取线程的状态
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
注意!一个线程在被从Object.wait()中被唤醒时,会立即进入BLOCKED状态,这时其并没有获得锁,只是被唤醒了,再次开始对Object的监视器锁进行竞争;只有在其竞争获得锁之后才会进入RUNNABLE状态.
四、run()和start()
run():如果是构造Thread
对象的时候,传入了该对象预期执行的任务----Runnable
对象时,执行该任务,否则,什么都不做,当然,可以通过继承Thread类重写run()来修改其行为:
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
start():以前面试最爱问的一个问题:调用start()与调用run()的区别?这还用说吗?调用run()只是普通的方法调动,执行的线程还是调用线程;而调用start()可以启动一个线程并是线程出入Runnable状态
/* 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 {
// 通过native方法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();
通过上述start()方法的源码,可以总结出以下几个点:
- (1) 当线程被构造完成之后,有个状态变量会记录线程的状态,就是上述的threadStatus,初始值在类中声明的为0;
- (2) 调用start方法启动线程之后,threadStatus的值会被改变。如果再次重复调用start方法启动同一个线程时,会抛出IllegalThreadStateException异常;
- (3) thread线程启动之后,会被加入到一个线程组ThreadGroup中;
- (4) 线程如果启动失败了,线程组会对线程做失败处理,将其从线程组中移除;
- (5) 如果一个线程生命周期结束了,再次调用start方法试图启动线程的时候,会提示IllegalThreadStateException异常,也就是处于TERMINATED状态的线程没办法重新回到RUNNABLE或者RUNNING状态;
下面是一个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;
}
}
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); //Interruptible中的一个方法,两个实现类主要在nio包中
return;
}
}
interrupt0();
}
private native void interrupt0();
/**
*判断是否产生中断,两个方法:interrupted() isInterrupted()
*/
public static boolean interrupted() {
//清除中断标志位
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 返回线程是否被打断(打断标志是否被置位)
* 传入的参数决定该方法是否会清除中断标志位
*/
private native boolean isInterrupted(boolean ClearInterrupted);
关于interrupt()方法的细节说明(以下是翻译自javadoc关于interrupt() 的说明):
- (1)interrupt()的作用是中断本线程。本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。
- (2)如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
- (3)如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时,线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
- (4)如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。
- (5)中断一个“已终止的线程”不会产生任何操作。
另外关于isInterrupted()和interrupted()的区别,上述源码表现得很明显isInterrupted()在执行后不会清除中断标志位,interrupted()在方法执行后会清除中断标志位,而且是个静态方法。
六、线程礼让\睡眠\合并—yield() sleep() join()
/**
* 暗示调度器让出当前线程的执行时间片,调度器可以选择忽略该暗示;
* 该方法在用来调试和测试时可能很有用,可以用来重现需要特殊条件才能复现的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
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如何解决内存泄漏问题?
/**
*每个线程的ThreadLocalMap
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/**
* InheritableThreadLocal提供了一种父子线程之间的数据共享机制。
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
九、UncaughtExceptionHandler
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* 设置UncaughtExceptionHandler,该设置对所有线程有效
* 如果自身没有设置,则交给其线程组的UncaughtExceptionHandler处理,如果再没有,
* 则交给默认的的UncaughtExceptionHandler处理,也即这里设置的UncaughtExceptionHandler处理
* 注意这里的设置不应该设置为线程的线程组,这样的设置会造成死循环
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
}
defaultUncaughtExceptionHandler = eh;
}
/**
* 返回默认的UncaughtExceptionHandler,该UncaughtExceptionHandler对所有线程有效
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* 返回该线程的UncaughtExceptionHandler,如果没有,返回该线程的线程组
* ThreadGroup本身实现了UncaughtExceptionHandler接口
*/
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);
}