## Java专题十三(1):线程
[TOC]
### 13.1.1.线程的定义
**进程是资源分配的最小单位,线程是CPU调度的最小单位**
电脑上开一个QQ应用程序就是一个进程,你用QQ与**甲**打电话的同时跟与**乙**文字聊天,打电话和文字聊天都是一个线程,这里使用2个线程来完成用户不同的操作,一个QQ进程包管理着多个线程
**线程生命周期**:
1. 新建(New)状态,当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值
2. 就绪(Runnable)状态,当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行
3. 运行(Running)状态,如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态
4. 阻塞(Blocked)状态,当处于运行状态的线程失去所占用资源之后,便进入阻塞状态
5. 死亡(Dead)状态,线程出错或者线程正常结束
![](https://img.kancloud.cn/e8/6f/e86f0c4600a837599d181caabdeda37c_632x485.png)
### 13.1.2.线程的创建
#### 13.1.2.1,实现Runnable接口
```
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();
```
#### 13.1.2.2.继承Thread类
```
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();
```
#### 13.1.2.3.使用Callable和Future
```
class PrimeThread implements Callable<Long> {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public Long call() throws Exception {
return this.minPrime;
}
}
PrimeThread p = new PrimeThread(143);
FutureTask task = new FutureTask(p);
new Thread(task).start();
System.out.println(task.get());
```
### 13.1.3.线程池(ThreadPoolExecutor类)
- **线程池的参数:**
~~~
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
~~~
**corePoolSize**:保存在线程池的线程数量,即使它们是空闲的
**maximumPoolSize**:允许加入到池中的最大线程数量
**keepAliveTime**:当线程数量比corePoolSize多时,为多余空闲线程终止之前等待新任务的最长时间
**workQueue**:线程池工作队列
**threadFactory**:创建线程的工厂类
- **ThreadPoolExecutor其它参数**
**workers**:工人集合
**workerCount**:有效线程的数量
**runState**:线程池的状态,running, shutting down等
1. RUNNING :接收新任务,处理已经入队的任务
2. SHUTDOWN : 不接收新任务,但处理已经入队的任务
3. STOP : 不接收新任务,不处理已经入队的任务,并且中断正在进行中的任务
4. TIDYING : 所有任务都完成 ,workerCount为零,该状态下的线程会调用terminated()方法
5. TERMINATED : 完成方法terminated()的执行
![](https://img.kancloud.cn/53/8f/538f575e9a263821217136d63cfd9b13_577x533.png)
为了更好理解线程池,先定义以下几个概念:
> 产品:实现了Runnable接口的线程类,用户提交的Task任务
> 工人:ThreadPoolExecutor#Worker类,负责新产品的包装工作和待包装产品线的产品包装工作
> 包装:线程Runnable接口的实现类中run()方法实际执行的代码
> 待包装产品线:workQueue队列,Task任务等待被执行
> 进口包装机:核心线程池,数量为corePoolSize
> 所有包装机:最大线程池,数量为maximumPoolSize
**=>线程池是怎么工作的呢?**
当有新的产品来时,首先查看进口包装机是否都被占着(`workerCountOf(c) < corePoolSize`),未被占着,就安排工人包装新产品,都被占着的话,接着看待包装产品线是否已满(`workQueue.offer(command)`),未满的话加入新产品,等待包装,否则,再看是否所有包装机都被用完了(`addWorker(command, false)`),没有,则安排工人包装新产品(`addWorker()`),否则不包装该产品(`reject(command)`)。
![](https://img.kancloud.cn/c6/b2/c6b21944bb870cb13a4823b8c7204747_1490x659.png)
```java
// ThreadPoolExecutor#execute
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
```
**=>工人是怎么工作的?**
首先在`ThreadPoolExecutor#addWorker`方法添加一个`Worker`对象(实现了`Runnable`接口),添加成功的话,启动`w.thread`线程,`Worker`内部调用`runWorker`方法,在`runWorker`方法,一方面做新产品包装工作(`task != null`->`task.run()`),另一方面做待包装产品线的产品包装工作(`(task = getTask()) != null`->`task.run()`)
```java
// ThreadPoolExecutor#addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// ...
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
// ThreadPoolExecutor#Worker
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
// ...
while (task != null || (task = getTask()) != null) {
// ...
task.run();
// ...
}
}
}
// ThreadPoolExecutor#getTask
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
```
- JavaCook
- Java专题零:类的继承
- Java专题一:数据类型
- Java专题二:相等与比较
- Java专题三:集合
- Java专题四:异常
- Java专题五:遍历与迭代
- Java专题六:运算符
- Java专题七:正则表达式
- Java专题八:泛型
- Java专题九:反射
- Java专题九(1):反射
- Java专题九(2):动态代理
- Java专题十:日期与时间
- Java专题十一:IO与NIO
- Java专题十一(1):IO
- Java专题十一(2):NIO
- Java专题十二:网络
- Java专题十三:并发编程
- Java专题十三(1):线程与线程池
- Java专题十三(2):线程安全与同步
- Java专题十三(3):内存模型、volatile、ThreadLocal
- Java专题十四:JDBC
- Java专题十五:日志
- Java专题十六:定时任务
- Java专题十七:JavaMail
- Java专题十八:注解
- Java专题十九:浅拷贝与深拷贝
- Java专题二十:设计模式
- Java专题二十一:序列化与反序列化
- 附加专题一:MySQL
- MySQL专题零:简介
- MySQL专题一:安装与连接
- MySQL专题二:DDL与DML语法
- MySQL专题三:工作原理
- MySQL专题四:InnoDB存储引擎
- MySQL专题五:sql优化
- MySQL专题六:数据类型
- 附加专题二:Mybatis
- Mybatis专题零:简介
- Mybatis专题一:配置文件
- Mybatis专题二:映射文件
- Mybatis专题三:动态SQL
- Mybatis专题四:源码解析
- 附加专题三:Web编程
- Web专题零:HTTP协议
- Web专题一:Servlet
- Web专题二:Cookie与Session
- 附加专题四:Redis
- Redis专题一:数据类型
- Redis专题二:事务
- Redis专题三:key的过期
- Redis专题四:消息队列
- Redis专题五:持久化