线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
继承关系图
线程的创建方式有很多种。常用的有:继承Thread(),重写该类的run()方法;实现Runnable接口,并重写该接口的run()方法。
其实Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。
主要属性
// 线程的名称 private volatile char name[]; // 线程的优先级 private int priority; // 是否是单步执行 private boolean single_step; // 是否是守护线程 private boolean daemon = false; // JVM虚拟机的状态 private boolean stillborn = false; // 将会被执行的 Runnable private Runnable target; // 当前线程的组 private ThreadGroup group; // 当前线程的上下文 private ClassLoader contextClassLoader; // 当前线程继承的访问控制权限 private AccessControlContext inheritedAccessControlContext; // 默认线程的自动编号 private static int threadInitNumber; // 得到下个thread ID private static synchronized int nextThreadNum() { return threadInitNumber++; } // 与当前线程有关的ThreadLocal值 ThreadLocal.ThreadLocalMap threadLocals = null; // 与当前线程相关的InheritableThreadLocal值。 ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; // 该线程请求的堆栈大小 默认一般为空 JVM自行分配 private long stackSize; // 当前线程终止后,JVM的私有状态 private long nativeParkEventPointer; // 当前线程的专属ID private long tid; // 用来生成 thread ID private static long threadSeqNumber; // 线程状态,0代表线程未启动 Runable private volatile int threadStatus = 0; // 中断阻塞器:当线程发生IO中断时,需要在线程被设置为中断状态后调用该对象的interrupt方法 volatile Object parkBlocker; // 阻塞器锁,主要用于线程中断 private volatile Interruptible blocker; private final Object blockerLock = new Object(); // 阻断锁 void blockedOn(Interruptible b) { synchronized (blockerLock) { blocker = b; } } // 线程优先级 最低优先级 public final static int MIN_PRIORITY = 1; // 线程优先级 默认优先级 public final static int NORM_PRIORITY = 5; // 线程优先级 最高优先级 public final static int MAX_PRIORITY = 10;
构造方法
我们平时惯用new Thread()方法去创建一个线程,实际上线程初始化的过程中已经完成了很多默认的配置
// init方法相关参数 // g 线程组 // target 实现 Runnable接口类对象,就是调用 run方法的目标对象 // name 线程名称 // stackSize 栈的大小 该值对JVM而言只是一个建议,JVM会动态选择更合适的值 // acc 访问控制权限 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(); // 获取系统的security SecurityManager security = System.getSecurityManager(); // 没有指定线程组的话,创建的所有线程属于相同的线程组。 if (g == null) { // 先将secuity的线程组赋给新线程的线程组 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); // 分配线程栈的大小 this.stackSize = stackSize; // 分配线程Id ThreadID是由JVM分配的,并不是系统的真正线程ID tid = nextThreadID(); } private void init(ThreadGroup g, Runnable target, String name, long stackSize) { init(g, target, name, stackSize, null); } 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); }
native方法
// 获得当前线程 public static native Thread currentThread(); // 使当前线程从 运行状态Running 变为 就绪状态 Runnable public static native void yield(); // 使当前线程进入休眠状态 public static native void sleep(long millis) throws InterruptedException; // 使线程进入就绪状态 Runnable private native void start0(); // 判断线程是否为中断状态 private native boolean isInterrupted(boolean ClearInterrupted); // 判断线程是否存活 public final native boolean isAlive(); // 获取所有线程列表 private native static StackTraceElement[][] dumpThreads(Thread[] threads); private native static Thread[] getThreads(); // 设置线程优先等级 private native void setPriority0(int newPriority); // 停止线程 该方法已被弃用 private native void stop0(Object o); // 线程暂停 private native void suspend0(); // 线程继续执行 private native void resume0(); // 线程中断 private native void interrupt0(); // 设置线程名 private native void setNativeName(String name);
这里不得不说和线程相关的几个Object Native方法。
// 随机唤醒在此对象监视器(锁)上等待的单个线程。 public final native void notify(); // 唤醒所有等待在该对象上的线程。 public final native void notifyAll(); // 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法 public final void wait() throws InterruptedException { wait(0); } // 超时等待一段时间,这里的参数是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。 public final native void wait(long timeout) throws InterruptedException;
我最开始有些疑惑,为什么wait(),notify(),notifyAll()用来操作线程会定义在Object类中?
不妨我们先做一个假设:将wait、notify和线程队列都放到Thread中,那么在wait、notify的调度过程中必然要求某个Thread知道其他所有Thread的信息,显然是不合理的。
而放到对象中,让对象维护所有竞争锁线程的队列,各个线程无必然联系。
关键方法
start() 启动线程
public synchronized void start() { // 判断线程状态是否启动,不允许同一线程启动2次! if (threadStatus != 0) throw new IllegalThreadStateException(); // 向线程组中添加当前线程 group.add(this); // 使线程进入就绪状态 Runnable 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 */ } } }
checkAccess() 检查当前线程是否有修改权限,该方法在线程状态变更前多次被调用
public final void checkAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { // 通过Java安全管理器检查当前线程是否有修改权限 security.checkAccess(this); } }
run() 使线程从就绪状态 Runnable转化为运行状态 Running -todo线程启动过程中由start到run的过程非常复杂。
public void run() { // 调用 run方法的目标对象 if (target != null) { target.run(); } }
exit() 该方法 run方法执行完成后调用,在线程结束退出之前进行清理工作。
private void exit() { // 释放资源 if (group != null) { group.threadTerminated(this); group = null; } target = null; threadLocals = null; inheritableThreadLocals = null; inheritedAccessControlContext = null; blocker = null; uncaughtExceptionHandler = null; }
stop() stop方法是不安全的,它会立即停止线程执行,线程的后续执行不连贯。可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。故被标记为@Deprecated
@Deprecated public final void stop() { SecurityManager security = System.getSecurityManager(); if (security != null) { checkAccess(); if (this != Thread.currentThread()) { security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION); } } if (threadStatus != 0) { resume(); // Wake up thread if it was suspended; no-op otherwise } stop0(new ThreadDeath()); }
interrupt() 中断线程
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(); }
setPriority()、getPriority() 设置、获取线程优先级
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; }
join() 在当前线程中调用另一个线程的join()方法,使当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
public final void join() throws InterruptedException { join(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"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
setDaemon() 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
public final void setDaemon(boolean on) { checkAccess(); // 该方法必须在启动线程前调用 if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; }