1、并发的基础
-
线程的基本概念
- 表示一条单独的执行流,有自己的程序执行计数器,自己的栈
- 两种创建方式:继承Thread;实现Runnable接口
- 无论哪种创建方式最后都需要调用start方法启动线程
-
synchronized
- 可用于修饰类的实例方法、静态方法和代码块
- 多个线程可以同时执行同一个synchronized实例方法,只要访问的对象不同即可,synchronized实例方法实际保护的是同一个对象的方法调用,确保同时只能有一个线程执行
- 可重入性
- 内存可见性
-
线程基本协作机制
- wait/notify方法只能在synchronized代码块内调用
-
线程的中断
- 中断不是强迫终止一个线程,而是一种协作机制,给线程传递一个取消信号,但是由线程决定如何以及何时推出
2、并发包的基石
-
原子变量和CAS
-
CAS:compareAndSet,比较并设置,有两个参数expect和update,以原子的方式实现:如果当前值等于expect则更新为update,否则不更新,如果更新成功返回true否则返回false
-
原子变量的更新逻辑是非阻塞式的,更新冲突的时候j就重试,不会阻塞,不会有上下文切换开销。synchronized代表一种阻塞式算法,得不到锁的时候进入锁等待队列,等待其他线程唤醒,有上下文切换开销。
-
显式锁
-
可重入锁ReentrantLock
1、可重入
2、解决竞态条件问题
3、保证内存可见性
-
yield只是告诉操作系统可以让其他线程运行,但自己依然式可运行状态,而park会放弃调度资格,使线程进入WAITING状态
-
AQS:可以保存锁当前持有线程,提供方法进行查询和设置,内部维护了一个等待队列,借助CAS实现无阻塞算法进行更新
-
显式条件
3、并发容器
-
CopyOnWriteArrayList
-
线程安全,可以被多个线程并发访问
-
迭代器不支持修改
-
内部是个数组,以原子方式被整体更新
-
读不需要锁,可以并行,多个线程不能同时写,每个写操作都需要先获取锁,内部使用ReentrantLock
-
CopyOnWriteArraySet:内部通过CopyOnWriteArrayList实现
-
ConcurrentHashMap
-
弱一致性:迭代器创建后,会按照哈希表结构遍历每个元素,遍历过程中内部元素如果在已遍历过的部分发生变化,迭代器就不会反映出来,如果在未遍历过的部分发生变化则迭代器就会发现并反映出来
-
并发版的HashMap,通过降低锁的粒度和CAS等实现高并发,支持原子条件更新
-
不会抛出ConcurrentModificationException,实现弱一致性
-
锁的粒度:锁住多大的范围
-
并发队列
-
无锁非阻塞并发队列:ConcurrentLinkedQueue和ConcurrentLinkedDeque
-
普通阻塞队列:基于数组的ArrayBlockingQueue,基于链表的LinkedBlockingQueue和LinkedBlockingDeque
-
优先级阻塞队列:PriorityBlockingQueue
-
延时阻塞队列:DelayQueue
-
其他阻塞队列:SynchronousQueue和LinkedTransferQueue
SynchronousQueue适用于两个线程之间直接传递信息、事件或任务
4、异步任务执行服务
-
基本概念和原理
-
Runnable接口没有返回结果,Callable有;Runnable不会抛出异常,而Callable会
-
线程池
-
两个概念:任务队列;工作者线程
工作者线程主体是一个循环不断从队列中接受任务并执行,任务队列保存待执行的任务
- 优点
1、重用线程,避免线程创建的开销
2、任务过多时通过排队避免创建过多线程,减少系统资源消耗和竞争