The All-in-One Note (12)

生产者用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总览图

The All-in-One Note

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阻塞队列BlockingQueue

ArrayBlockingQueue

结构:由数组组成的有界阻塞队列

LinkedBlockingQueue

结构:由链表组成的有界/无界阻塞队列

LinkedTransferQueue

结构:由链表组成的无界阻塞队列

LinkedBlockingDeque

结构:由链表组成的双端阻塞队列

PriorityBlockingQueue

结构:由堆结构支持优先级排序的无界阻塞队列

DelayQueue

结构:使用PriorityQueue实现的带延迟的无界阻塞队列

SynchronousQueue

结构:不存储元素的阻塞队列

线程池的五种状态

The All-in-One Note

如何创建线程池

结构图

The All-in-One Note

直接通过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 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyysp.html