目前,基本上所有操作系统都支持多任务的执行,对计算机来说,每一个人物就是一个进程,而在每一个进程内部,都至少有一个线程正在运行。我们有时称线程是轻量级的进程。线程是程序执行的路径,每一个线程都拥有自己的局部变量表,程序计数器以及各自的生命周期。
线程的生命周期其实还是很好理解的,分为 New, Runnable, Running, Blocked, Terminated 五个阶段,包含了线程从创建、到运行、再到死亡的全过程。
当我们用关键字new创建一个Thread对象时,线程处于New状态。本质上,这只是一个普通的Java对象。当然,我们调用start()方法就可以进入Runnable状态。
进入 Runnable 状态后,线程加入线程池等待CPU的调度。执行了,但没有完全执行。由于存在Running状态,所以不会直接进入Blocked或者Terminated状态。严格来说,Runnable只能意外终止或者进入Running。
Runnable状态或者CPU调度后,进入Running状态,开始运行线程的执行单元。
初始状态 | 转换状态 | 原因 |
Running | Runnable | CPU调度器轮询要求线程放弃执行 主动调用yield |
Running | Blocked | 调用sleep/wait/join方法 进行某个阻塞的IO操作 获取某个同步锁资源 |
Running | Terminated | 调用stop或者JVM Crash |
一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引用阻塞的原因,被消除后,线程才可以进入就绪状态。
线程的run()方法正常执行完毕,线程抛出一个未捕获的异常或错误或者JVM崩溃,线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不能转换为其他状态。
public class Thread implements Runnable { // 我们忽略一些目前不太重要的参数 // 线程名 private volatile String name; // 优先级 private int priority; // 是否是守护线程 private boolean daemon = false; // 是否导入Runnable作为参数,如果target为空,就会执行run()方法,否则运行target private Runnable target; // 确定线程组 private ThreadGroup group; // 类加载器,待补充 private ClassLoader contextClassLoader; // 访问控制,待补充 private AccessControlContext inheritedAccessControlContext; // 如果Thread没有定下名字,这个数字用来自动生成"Thread-1"这样子的名字。 private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; } /* * 线程栈的大小 * The requested stack size for this thread, or 0 if the creator did * not specify a stack size. It is up to the VM to do whatever it * likes with this number; some VMs will ignore it. */ private final long stackSize; /* * 线程 ID */ private final long tid; /* For generating thread ID */ private static long threadSeqNumber; private static synchronized long nextThreadID() { return ++threadSeqNumber; } /* * Java thread status for tools, default indicates thread 'not yet started' */ private volatile int threadStatus; ... }
public class Thread implements Runnable { ... /* 这个是私有的构造函数,公开的构造函数很多都是选取其中部分参数 */ private Thread(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; // 确定父进程 Thread parent = currentThread(); // 获取SecurityManager 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) { g = security.getThreadGroup(); } /* If the security manager doesn't have a strong opinion on the matter, use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission( SecurityConstants.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 (inheritThreadLocals && 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 */ this.tid = nextThreadID(); } ... }
public class Thread implements Runnable{ ... public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ // 如果线程状态不为NEW, 报错 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 { // C/C++写的本地方法,真正开始运行逻辑 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 */ } } } ... }
总共有两种方法创建线程。一种是创建一个Thread类的子类,这个子类应当重写run()方法。
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
运行方法:
PrimeThread p = new PrimeThread(143); p.start();
另一种则是实现Runnable接口,并将其作为参数传递给Thread类。
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
运行方法:
PrimeRun p = new PrimeRun(143); new Thread(p).start();