java.lang.Thread
java.lang.Runnable
JUC:java.util.concurrent下的包
Executor顶级接口
ExecutorService :ExecutorService 是 Executor 的扩展,提供了管理线程的方法,如关闭服务、提交依赖于关闭状态的任务等。
ThredaPoolExecutor:ExecutorService的具体实现
Lock
ReentrantLock :可重入锁
Condition:与ReentrantLock实现多线程通信
ReadWriteLock/ReentrantReadWriteLock:读写锁
线程通信
- volatile共享内存
- synchronized互斥临界区,使用了Object提供的方法wait():再synchronized内部调用,线程释放锁进入等待状态 ,notify()、notifyAll():调用者获得了锁,唤醒处于等待状态的线程,如果有多个等待状态线程随机唤醒一个。唤醒后不一定立即获得锁执行,因为线程调度是操作系统决定的。
- ReentrantLock和Condition多线程消息通信,通过调用Condition的await()方法和signal()、signalAll()方法实现等待状态与运行状态切换
- CountDownLatch:通过一个计数器实现
- 信号量机制
- 管道
线程安全
多个线程同时执行代码不会产生混乱,能得到正确的结果
线程与进程
进程是操作系统分配资源的基本单位,每个进行有独立地址空间,不同的进程之间是隔离的。
每个进程至少有一个线程,也可以多个线程并发执行。
线程是操作系统调度的最小单元,同一个进程中的线程共享进程的资源
创建线程的成本比创建进程的成本低,切换线程消耗比进程低
并发与并行
线程创建方式
底层都是Runnable
匿名内部类写法
Lambda表达式
为什么不建议使用Executors创建线程池?
1、FiexdThreadPool创建持有无界队列的线程池,如果任务过多会导致内存占用过多,导致内存耗尽,OOM。
2、SingleThreadPool创建一个只有一个工作线程的线程池,但是会导致任务充满线程池导致OOM
使用ThreadPoolExectors创建线程池 ,我们可以灵活定义线程池中的各种参数,对线程池底层更加清晰。
线程参数:核心线程数、最大线程数、等待时间、时间单位、任务队列、线程工厂、拒绝策略(
- 抛异常,抛出RejectedExecutionException来拒绝新任务的处理。
- 直接丢弃
- 调用者线程执行
- 丢弃任务队列中最老的任务);
线程池状态
RUNNING:线程池运行状态
ShutDown:调用shutdown()方法进入ShutDown状态,不在接受新任务,但是会处理玩队列中的任务
Stop:调用shutdownNow()方法进入Stop状态,不接受新任务,也不会处理队列中的任务
TIDYING:线程池中没有运行的线程会自动变为tidying
TERMINATED:调用terminated()方法进入。
线程状态
线程并发安全
synchroized
monitor
Synchorized
JMM
乐观锁与悲观锁
悲观锁:悲观锁就像他的名字一样,他的基本思想就是假设每次都会有线程安全问题,所以每次访问资源都采用加锁的方式来避免线程安全问题。数据库中:行锁、共享锁、排他锁;java:synchronized、ReentrantLock;
乐观锁:乐观锁基本思想是每次对资源的访问不存在线程安全问题,因此直接操作数据,操作完成后通过某些机制来判断是都在此期间数据倍更改过,如果被更改则操作失败,否则操作成功。版本号机制、CAS
CAS
volatile
1、 保证线程间的可见性
volatile修饰共享变量,当一个线程修改了共享变量,能够防止编译器等优化发生,让一个线程对共享变量的修改对其他线程可见。(当一个线程修改了一个被 volatile 修饰的共享变量后,这个修改后的值会立即反映到主内存中。其他线程读取这个变量时,会从主内存中读取最新的值,而不是从线程的工作内存中读取可能过期的副本。这样就保证了不同线程间对这个变量的可见性。)
2、禁止指令重排序
volatile修饰的共享变量会在读写共享变量时加上一个屏障,阻止其他的读写操作越过共享变量,达到阻止指令重排序效果。
3、防止优化
JVM中可能会对代码进行优化,如果一个变量只读取不修改,那么JVM可能会缓存这个变量值,不再从主内存中读取最新值。
AQS
Lock与sychroized
ReentrantLock
底层都是使用AQS来实现排队的,当使用lock()加锁时,如果是公平锁,会先检查AQS队列中是否有正在排队的线程,如果有当前线程也加入排队,如果非公平锁,不去检查是否有线程在排队,直接竞争锁。
死锁
concurrentHashMap
并发线程安全问题
线程池
核心线程数
3
线程池种类
线程池使用
线程池拒绝策略
1、中止策略:当线程池无法接受新任务时,抛出异常,不再处理新提交的任务。
2、丢弃策略:当线程池无法接受新任务时,直接丢弃任务,不处理也不抛出异常。
3、丢弃最旧任务:当线程无法接受新线程时,丢弃最旧任务,执行新任务。
4、调用者运行策略:该策略会让调用execute()方法的线程直接执行任务。