# 线程
# 实现线程的方法
- Runnable
- Callable
- 继承Thread类
解耦、复用线程提高性能
# 停止线程的方式
interrupt可以通知被停止线程,以实现线程间相互通知、相互协作
while (!Thread.currentThread().isInterrupted() && 有工作要做) {
做
}
1
2
3
2
3
原理:
- 调用某个线程的
interrupt()
后,这个线程的中断标记位就会被设置成true
- 休眠中的线程(
sleep
、wait
等可以使线程进入阻塞)是可以感受到中断信息的,并且会抛出InterruptedException
,同时清除中断信息,将标记位设置为false
Thread.currentThread().interrupte()
函数可以手动添加中断信息
错误用法:
suspend()
、resume()
:线程调用后,不会释放锁,就进入休眠,在调用resume()
前,不会释放,容易引起死锁问题volitile
:生产者消费者模式下,生产者阻塞,在它被叫醒之前无法判断结束标记值。而消费者不消费数据时设置的结束标记有可能永远无法读到
private volatile boolean canceled =false;
try {
while (!cancled && 有工作要做) {
工作
}
} catch (InterruptedException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
正确使用interrupt
的方式:
- 用它请求中断,而不是强制停止
- 中断的异常处理
- 声明在方法中,顶层可以感知并捕获到;
catch
后再次声明中断,以便下次仍可感知到
# 线程状态
New 新创建
new Thread()
没有调用start()
,调用后转为Runnable
状态
Runnalbe 可运行
Blocked(Synchroined Lock)被阻塞
等待其它线程释放monitor锁(等待获取排它锁)
- 进入
synchronized
没有获取到锁
- 进入
Waiting(Object.wait,Thread.join,LockSupoport.pack,Object.notify)无限期等待,否则不会分配时间版 等待某个条件,等待其它线程显示唤醒,比如join的线程执行完毕,或者
notify() notifyAll()
- 没有Timeout参数的Object.wait()
- 没有Timeout参数的Thread.join()
- LockSupport.park()-------ReentrantLock本质执行了它
TImeWaiting:限期等待
- 设置时间参数的Thread.sleep
- 设置时间参数的Object.wait
- 设置时间参数的Thread.join
- 设置时间参数的LockSupport.packNanos和LockSupport.parkUntil方法
Terminated 被终止
延时等待状态:不会释放任何资源及监视器
等待阻塞状态:会暂时释放相关线程资源及监视器
# Wait必须在Synchronized同步代码中
- 生产者消费者模式下,确保notify方法不会消费者判空和wait之间执行
- Wait会释放monitor锁,所以必须在Synchronized中持有这把锁
# 生产者消费者的实现
BlockQueue
Condition
private Queue queue = new LinkedList(); private int max = 16; private ReentrantLock lock = new ReentrantLock(); // 没有空 private Condition notEmpty = lock.newCondition(); // 没有满 private Condition notFull = lock.newCondition(); public void put(Object o) { lock.lock(); try { while (queue.size() == max) { notFull.await(); } queue.add(o); notEmpty.signal(); } finally { lock.unlock(); } } public Object take() { lock.lock(); try { while(queue.size() == 0) { notEmpty.await(); } Object item = queue.remove(); notFull.signalAll(); return item; } finally { lock.unlock(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34wait notify
private int maxSize = 16; private LinkedList<Object> storage = new LinkedList<>(); public synchronized void put() { while (storage.size() == maxSize) { wait(); } storge.add(new Object()); notifyAll(); } public synchronized void take() { while(storage.size() == 0) { wait(); } Object o = storage.remove(); notifyAll(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 线程安全
- 运行结果
- 多个线程操作同一份数据
- 发布和初始化
- 活跃性问题
- 死锁:线程间相互等待资源,又不让出已占有的资源
- 活锁:程序一直在执行,却拿不到结果
- 饥饿:程序一直拿不到锁,无法执行
# 线程安全问题场景
- 访问共享变量或资源
- 操作依赖时序
- 不同数据之间需要原子的同时修改
- 并发环境下使用其它类,但其它类没有声明自己是线程安全的
# 线程池
- 解决线程生命周期系统开销的问题
- 统筹内存和CPU的使用,避免资源使用不当
- 统一管理资源
线程池参数
参数 | 含义 |
---|---|
corePoolSize | 核心线程数 |
maxPoolSize | 最大线程数 |
keepAliveTime | 空闲线程存活时间 |
ThreadFactory | 线程工厂,用来创建线程 |
workQueue | 任务队列 |
Handler | 拒绝任务策略 |