线程状态
- New(新建):刚new Thread()创建,还没开始运行run
- Runnable(可运行):调用start方法,可能正在运行也可能没有运行
- Blocked(阻塞):要获得一个锁
- Waiting(等待):等待通知
- Timed waiting(计时等待):等待超时或通知
- Terminated(终止):运行结束或异常结束
中断线程
- 对一个线程实例调用interrupt()方法会向该线程发送一个中断请求,并将该线程的中断状态设置为true
- 如果一个线程处于等待或者阻塞状态时,收到中断请求会抛出InterruptedException异常
- 线程可以通过Thread.currentThread().isInterrupted()来获取当前线程的中断状态
未捕获异常的处理器
- 自定义实现 Thread.UncaughtExceptionHandler接口的类
- 可以用setDefaultUncaughtExceptionHandler为所有线程配置一个默认的处理器,也可以为单个线程配置
- 单个线程默认的处理器是该线程的ThreadGroup对象
锁对象
- 接口:
java.util.concurrent.locks.Lock
- 实现类:
java.util.concurrent.locks.ReentrantLock
可重入锁,可以反复获取已经拥有的锁。锁有一个持有计数来跟踪对lock方法的嵌套调用,线程每一次调用lock后都要调用unlock来释放锁。由于这 个特性,被一个锁保护的代码可以调用另一个使用同一个锁的方法。 - 获取锁对象:
Lock lock = new ReentrantLock()
- 上锁:
lock.lock()
- 释放锁:
lock.unlock()
条件对象
接口:java.util.concurrent.locks.Condition
获取条件对象:Condition condition = lock.newCondition()
将该线程放在这个条件的等待集中:condition.await()
解除该条件等待集中所有线程的阻塞状态:condition.singnalAll()
Lock和Condition总结
- 锁用来保护代码片段,一次只能有一个线程执行被保护的代码
- 锁可以管理试图进入被保护代码段的线程
- 一个锁可以有一个或多个相关联的条件对象
- 每个条件对象管理那些已经进入被保护代码段但不能运行的线程
synchronized关键字
同步方法
- java中每个对象都有一个内部锁,并且这个锁只有一个内部条件。
- 如果一个实例方法声明时有synchronized关键字,那么该实例对象的锁将保护整个方法。
- 如果一个静态方法声明有synchronized,那么该类对象(Class)的内部锁保护整个方法
- wait() / notify() / notifyAll() /
同步块
使用一个对象的锁来实现额外的原子操作。
synchronized(obj){
...
}
volatile
- volatile关键字为实例字段的同步访问提供了一种免锁机制。如果声明一个字段为volatile,那么编译器和虚拟机就知道该字段可能被另一个线程并发更新。
final变量
final HashMap<String,Integer> map = new HashMap<>();
如果不使用final,不能保证其他线程看到的是map更新后的值,可能看到null,而不是Hashmap。
当然map的操作不是线程安全的。
原子性
java.util.concurrent.atomic包下面有很多原子操作的类,不加锁实现原子操作,
线程安全的集合
位于java.util.concurrent包下
阻塞队列blocking queue
很多线程安全的问题都可以使用一个或多个队列以优雅而安全的方式来描述,生产者线程向队列插入元素,消费者线程则获取元素。使用队列可以安全地从一个线程向另一个线程传递数据。
标准类库中提供的阻塞队列:
接口:
- java.util.concurrent.BlockingQueue
- java.util.concurrent.BlockingDeque
实现:
- ArrayBlockingQueue:指定容量,可以设置公平性,实现为循环数组
- LinkedBlockingQueue:无容量上线的阻塞队列或双向队列,实现为链表
- LinkedBlockingDeque:无容量上限的包含Delayed元素的阻塞队列
- DelayQueue
- PriorityBlockingQueue:无容量上限,实现为堆
任务和线程池
Callable与Fature
- Callable
封装一个异步执行的任务,并且有返回值 - Fature
保存异步计算的结果
FutureTask
执行Callable的一种方式是FutureTask,它实现Future和Runnable接口,可以构造一个线程来运行这个任务
执行器Executors
执行器有很多静态工程方法,用来构造线程池。返回的都是实现了ExecutorService接口的实例。
控制任务组
fork-join
用于将一个大任务分解成子任务,并行处理,最后再汇总结果
异步计算
- Future通过get方法获取值时会阻塞,直到值可用。
- CompleableFuture类可以通过注册一个回调,一旦值可用,就会通过结果调用这个回调。
- CompletableFuture有很多同步和异步的方法,可以组合这些方法实现不同效果。