生产者用extends,消费者用super
public class NewStack<T>{ public void pushAll(Iterable <? extends T> src) { for (T t : src) { push(t); } } public void popAll(Collection <? super T> dst){ while (!isEmpty()){ dst.add(pop()); } } } J.U.C总览图 J.U.C常用同步器CountDownLatch
作用:主要用于线程要等待其他线程任务执行完再执行,等到条件满足之后一起起跑
CyclicBarrier
作用:可以重复利用的CountDownLatch
Executors
作用:主要用于提供默认应用场景的线程池创建,以及一些任务调度方法
Semaphore
作用:主要用于限制同时执行任务的线程数量
Exchanger
作用:主要用于两个线程之间交换数据
AbstractQueuedSynchronizer(AQS)大致原理
CAS
CLH
LockSupport
Condition
大名鼎鼎的AQS,这里涉及源码较多,就贴连接吧
一行一行源码分析清楚AbstractQueuedSynchronizer
一行一行源码分析清楚AbstractQueuedSynchronizer-2
一行一行源码分析清楚AbstractQueuedSynchronizer-3
ReentrantLock
特征
公平锁
非公平锁
非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了。
非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面。
可重入
实现
AQS
lockSupport + CAS + CLH
过程
加锁过程 reentrantLock.lock()
acquire()要锁
tryAcquire()尝试拿锁
如没拿到锁,则addWaiter()加入等待队列
加入等待队列冲突了,则enq()自旋的插入队列
然后acquireQueued()循环的拿等待队列的头去抢锁
没抢到的线程都要被挂起shouldParkAfterFailedAcquire(), LockSupport.park()
解锁过程 reentrantLock.unlock()
release()解锁
tryRelease()尝试解锁
unparkSuccessor()唤醒阻塞队列的后继,LockSupport.unpark()
然后也进acquireQueued()
J.U.C阻塞队列BlockingQueueArrayBlockingQueue
结构:由数组组成的有界阻塞队列
LinkedBlockingQueue
结构:由链表组成的有界/无界阻塞队列
LinkedTransferQueue
结构:由链表组成的无界阻塞队列
LinkedBlockingDeque
结构:由链表组成的双端阻塞队列
PriorityBlockingQueue
结构:由堆结构支持优先级排序的无界阻塞队列
DelayQueue
结构:使用PriorityQueue实现的带延迟的无界阻塞队列
SynchronousQueue
结构:不存储元素的阻塞队列
线程池的五种状态 如何创建线程池结构图
直接通过new ThreadPoolExecutor()创建(推荐,可以定制化,控制细节)
构造参数:
int corePoolSize:线程池正常运行时的核心线程数,即使空闲也会等待任务在线程数少于核心数量时,有新任务进来就新建一个线程,即使有的线程没事干,等超出核心数量后,就不会新建线程了,空闲的线程就得去任务队列里取任务执行了
int maximumPoolSize:线程池允许的最大线程数
如果任务队列满了,并且池中线程数小于最大线程数,会再创建新的线程执行任务
long keepAliveTime:超出corePoolSize的线程的存活时间
TimeUnit unit:keepAliveTime参数的时间单位
BlockingQueue workQueue:核心线程全在干活,新任务进去这个阻塞队列等待执行,只有执行execute方法时才会进入等待队列
ThreadFactory threadFactory:创建新线程的工厂
RejectedExecutionHandler handler:workQueue满了,池中线程数也到了maximumPoolSize,就需要执行拒绝策略
CallerRunsPolicy:只要线程池没关闭,就直接用调用者所在线程来运行任务
AbortPolicy:直接抛出 RejectedExecutionException异常
DiscardPolicy:悄悄把任务放生,不做了
DiscardOldestPolicy:把队列里待最久的那个任务扔了
可能抛出的异常:
IllegalArgumentException
corePoolSize < 0
keepAliveTime < 0
maximumPoolSize <= 0
maximumPoolSize < corePoolSize
NullPointerException
workQueue,threadFactory和handler其中有一个为null
通过Executors工具类创建内置常用的线程池方案
newFixedThreadPool 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量