JUC
java.util.comcurrent:线程处理工具包
进程:计算机的程序关于某数据集合的一次运行活动。是系统进行资源分配和调度的基本单位,是操作系统结构的基础
线程:是操作系统能够进行运算调度的最小单位,是进程的实际运作单位
线程状态
Thread.State
public enum State{
NEW,(新建)
RUNNABLE,(准备就绪)
BLOCKED,(阻塞)
WAITING,(不见不散)
TIMED_WAITING,(过时不候)
TERMINATED(终结)
}
wait()和sleep()区别:
(1)sleep()是Thread的静态方法,wait()是Object的方法,任何对象实例都能调用
(2)sleep()不会释放锁,wait()会释放锁,前提是代码要在synchronized中
并发与并行区别
并发:同一时刻多个线程访问同一资源,多个线程对一个点
并行:多项工作一起执行,最后再汇总
synchronized同步锁
synchronized是java关键字,是内置特性,系统会自动让线程释放对锁的占用
(1)同步代码块:修饰一个代码块,作用的对象是调用这个代码块的对象
(2)同步方法:修饰一个方法,作用的范围是整个方法,作用的对象是调用这个方法的对象
(3)同步静态方法:修饰一个静态方法,作用的范围是整个静态方法,作用的对象是这个类的所有对象
(4)同步类:修饰一个类,作用的范围是整个类,作用的对象是这个类的所有对象
Lock接口
必须主动释放锁,一般采用try…catch…finally块结构。
线程通信
synchronized实现
在synchronized中通过wait()和notify()来实现等待/通知模式
Lock实现
通过Lock锁的 newCondition()方法返回的Condition类对象实现等待/通知模式
await():会使当前线程等待,同时会释放锁,当其他线程调用signal()方法时,线程会重新获得锁并继续执行
signal():用于唤醒一个等待的线程
Lock定制化通信
集合线程安全
List
ArrayList线程不安全
针对ArrayList线程不安全解决方式:
(1)Vector
(2)使用Collections类的synchronizedList(List list)对原list进行转换
(3)使用CopyOnWriteArrayList初始化list
Set
Map
锁类型介绍
死锁
查看程序是否存在死锁
(1)先使用jps查看进程号
(2)使用jstack 进程号来查看
公平锁
悲观锁
悲观锁不支持并发操作,效率低 乐观锁支持并发操作,操作完成后会修改版本号,另一线程提交时会判断版本号是否一致(不一致则提交失败)
可重入锁
Lock
synchronized
Callable接口
辅助类
CountDownLatch:减少计数
CyclicBarrier:循环栅栏
Semaphore:信号灯
读写锁
读锁(共享锁):ReentrantReadWriteLock.readLock()
写锁(排他锁或独占锁):ReentrantReadWriteLock.writeLock()
锁降级
产生死锁原因
阻塞队列
当队列是空的,从队列中获取元素的操作会被阻塞
当队列是满的,从队列中添加元素的操作会被阻塞
队列中没有数据的情况下,消费者端所有线程都会被自动阻塞(挂起),直到有数据放入队列
队列中填满数据的情况下,生产者端所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒
核心方法:
常见BlockingQueue:
(1)ArrayBlockingQueue:基于数组的阻塞队列实现,内部维护了一个定长数组,以便缓存队列中的数据对象
(2)LinkedBlockingQueue:基于链表的阻塞队列,内部维护着一个数据缓冲队列(由链表构成)
线程池
线程池维护着多个线程,等待着管理者分配可并发执行的任务,避免了处理短时间任务时创建和销毁线程的代价。不仅能保证内核的充分使用,还能防止过分调度
Java线程池是通过Executor框架实现
线程池创建
Executors方式(学习用)
(1)一池N线程:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
// 获取指定数量的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
(2)一池一线程:创建一个使用单个worker线程的Executor,以无界队列方式来运行该线程
// 获取单个线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
(3)可扩容线程池:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空线程,若无可回收则新建线程
// 获取可扩容的线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
自定义方式(生产用)
Executors方式创建线程池,底层源码都是new ThreadPoolExecutor()对象
ThreadPoolExecutor构造参数:
public ThreadPoolExecutor(
int corePoolSize,//常驻线程数量
int maximumPoolSize,//最大线程数量
long keepAliveTime,//线程存活时间
TimeUnit unit,//线程存活时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler//拒绝策略
)
线程池注意事项
(1)在创建线程池后,池中线程数为零,知直到执行execute()方法线程才创建
(2)当提交任务数 > 阻塞队列容量 + 最大线程数量时,就会触发线程池的拒绝策略
线程池拒绝策略
(1)AbortPolicy(默认):直接抛出RefectedExecutionExecption异常阻止系统正常运行
(2)CallerRunPolicy:”调用者运行“,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量
(3)DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
(4)DiscardPolicy:该策略摸摸丢弃无法处理的任务,不予任何处理也不排抛出异常
线程池工作原理
Fork/Join
将一个大任务拆分成多个子任务并行处理,最后将子任务结果合并成最后的计算结果
Fork: 将复杂任务进行分拆,大事化小
Join:把分拆任务的结果进行合并
涉及类:
(1)分支合并池:ForkJoinPool
(2)递归任务:抽象类ForkJoinTask(子类RecursiveTask)
异步编程(CompletableFuture)
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
Future接口兼容现有线程池框架
CompletionStage接口是异步编程的接口抽象