Thread继承体系
Thread的签名如下,继承了实现Runnable接口
public class Thread implements Runnable
Thread基本概念
线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。
当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称
Thread的属性
//线程名
private char name[];
//线程优先级
private int priority;
/* Whether or not to single_step this thread. */
private boolean single_step;
//是否是守护线程
private boolean daemon = false;
//虚拟机状态
private boolean stillborn = false;
//实际运行的对象,Runnable实例
private Runnable target;
//线程组对象
private ThreadGroup group;
//上下文类加载器
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
private long stackSize;
private long nativeParkEventPointer;
private long tid;
private static long threadSeqNumber;
private volatile int threadStatus = 0;
//interrupt status(中断状态)
volatile Object parkBlocker;
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
//最小优先级
public final static int MIN_PRIORITY = 1;
//默认优先级
public final static int NORM_PRIORITY = 5;
//最大优先级
public final static int MAX_PRIORITY = 10;
Thread构造函数
构造线程需要:ThreadGroup线程组, Runnable线程实例, name线程名, stackSize线程栈大小 AccessControlContext acc
如果没有设置线程组,则使用父线程线程组
如果没有设置线程实例,则为null
如果没有设置线程名称,则默认为:Thread-nextThreadNum
如果没有设置线程栈大小,则为0
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);
}
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) {
//线程名称不能为空
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
//设置父线程为当前线程
Thread parent = currentThread();
//获取JVM安全管理器
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) {
//返回一个新的线程被实例化的ThreadGroup
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();
}
}
//检测当前线程是否有操作线程组的权限
g.checkAccess();
/*
* Do we have the required permissions?
*/
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();
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
Thread的native方法
//返回当前线程执行对象
public static native Thread currentThread();
//使当前执行线程暂停一会,让其它线程得以执行。只是临时让出时间片,不会释放拥有的锁。
public static native void yield();
//使当前执行线程休眠指定的时间,不释放持有的锁
public static native void sleep(long millis) throws InterruptedException;
//测试线程是否被中断,中断状态是否被重置依赖于传入的ClearInterrupted参数值
private native boolean isInterrupted(boolean ClearInterrupted);
//测试线程是否活着,如果线程启动且没有死亡,那么线程是活跃状态
public final native boolean isAlive();
//计算该线程中的堆栈帧数。线程必须挂起。
public native int countStackFrames();
//当且仅当当前线程在指定的对象上保持监视器锁时,才返回true。该方法旨在使程序能够断言当前线程已经保持一个指定的锁
public static native boolean holdsLock(Object obj);
//导出线程栈数据
private native static StackTraceElement[][] dumpThreads(Thread[] threads);
//获取所有的线程快照
private native static Thread[] getThreads();
//设置线程优先级
private native void setPriority0(int newPriority);
//线程启动
private native void start0();
//停止线程
private native void stop0(Object o);
//状态当前线程
private native void suspend0();
//继续执行当前线程
private native void resume0();
//这种当前线程的中断标识(没有中断)
private native void interrupt0();
Thread的ID
//默认线程名的自增
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
//线程ID的自增
private static long threadSeqNumber;
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
Thread启动
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
//通知线程组线程启动,该线程会被添加到线程组活跃线程数组中,并且活跃线程数加一,未启动线程数量减一
group.add(this);
boolean started = false;
try {
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();
Thread睡眠
//睡眠:毫米,纳秒
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的中断
线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。它并不像stop方法那样会中断一个正在运行的线程。
判断某个线程是否已被发送过中断请求,请使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false),而不要使用thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)方法来判断。
如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法(sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法)调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
没有任何语言方面的需求一个被中断的线程应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断。某些线程非常重要,以至于它们应该不理会中断,而是在处理完抛出的异常之后继续执行,但是更普遍的情况是,一个线程将把中断看作一个终止请求
//interrupt status(中断状态)
volatile Object parkBlocker;
//测试线程中断但不清除中断状态
public boolean isInterrupted() {
return isInterrupted(false);
}
//测试线程中断并清除中断状态,parkBlocker会被置为空
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
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);
Thread的join
join() 方法是让调用该方法的主线程执行run()时暂时卡住,等run()执行完成后, 主线程再调用执行join()后面的代码。 join()方法会是当前线程等待,
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ThreadTesterA());
Thread t2 = new Thread(new ThreadTesterB());
t1.start();
t1.join(); // wait t1 to be finished
t2.start();
t2.join(); // in this program, this may be removed
}
t1.join()会是当前线程(即main线程处于等待状态,器等待t1线程结束才会继续执行)
//让当前线程一直等待,知道线程结束
public final void join() throws InterruptedException {
join(0);
}
//让当前线程等待一段时间执行,如果参数为0则永远等待
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=0,则一直等待,知道线程结束
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
// 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
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);
}