文章目录
java并发包笔记一
Semaphore和Exchanger
Semaphore
作用
Semaphore的功能是synchronized关键字的升级版,主要作用是控制线程并发的数量
通过发放许可permit来限制并发量,发放许可的计算方式是'减法'操作
Exchanger主要作用可以使2个线程之间互相方便地进行通信
API
public class Semaphore
extends Object
implements Serializable
void acquire()
void acquire(int permits)
void acquireUninterruptibly() // 使等待进入acquire方法的线程,不允许被中断
void acquireUninterruptibly(int permits)
int availablePermits() // 可获得的许可数量
int drainPermits() // 可获取并返回立即可用的所有许可数量,然后重置许可为0
protected Collection<Thread> getQueuedThreads()
int getQueueLength() // 获取等待许可的线程个数
boolean hasQueuedThreads() // 判断是否有线程在等待许可
boolean isFair()
protected void reducePermits(int reduction)
void release()
void release(int permits)
String toString()
boolean tryAcquire() // 是否能获取到许可,能则获取并返回true否则返回false并向下运行,不阻塞
boolean tryAcquire(int permits) // 尝试获取指定许可并返回结果,不阻塞
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
boolean tryAcquire(long timeout, TimeUnit unit) // 在指定的时间内尝试地获取1个许可,获取不到返回false,即阻塞timeout时间
public class Exchanger
extends Object
V exchange(V x)
V exchange(V x, long timeout, TimeUnit unit)
Semaphore的同步性
Semaphore的构造函数参数permits是许可的意思,代表同一时间内,最多允许多少线程同时执行acquire()和release()之间的代码
其中无参方法acquire()的作用是使用一个许可,是减法操作
Semaphore(int permits)
Creates a Semaphore with the given number of permits and nonfair fairness setting.
Semaphore(int permits, boolean fair)
Creates a Semaphore with the given number of permits and the given fairness setting.
public class SemaphoreDemo {
private Semaphore semaphore = new Semaphore(1);
public void testMethod(){
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis());
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SemaphoreDemo demo = new SemaphoreDemo();
Thread a = new Thread(demo::testMethod;
a.setName("a");
Thread b = new Thread(demo::testMethod;
b.setName("b");
a.start();
b.start();
}
执行结果
a begin timer=1544248257493
a end timer=1544248262493
b begin timer=1544248262493
b end timer=1544248267494
private Semaphore semaphore = new Semaphore(1);
来定义最多允许一个线程执行acquire()和release()之间的代码故而打印的结果是两个线程同步
Semaphore构造方法permits参数作用
参数permits的作用是设置许可的个数,若permits为1则只允许一个线程可以执行acquire()和release()之间的代码,是线程安全的(同步);
若permits的值大于1则该类并不能保证线程安全性;
方法acquire(int permits)参数作用及动态添加permits许可数量
有参方法acquire(int permits)的功能是每调用1次此方法,就使用x个许可
有参方法release(int permits)的功能是每调用1次此方法,释放x个许可
以上两个方法动态调整许可的个数
无参方法acquir()默认获得一个许可
无参方法release()默认释放一个许可
方法acquireUninterruptibly()
等待许可的情况下不允许中断,若成功获得锁,则获得指定参数许可的数量
acquireUninterruptibly()
acquireUninterruptibly(int permits)
中断实例:
在线程运行时调用该线程的interrupt方法导致中断异常InterruptedException
thread.interrupt();
此时使用acquireUninterruptibly防止被中断,但无法阻止sleep遇到interrupt抛出中断异常
公平和非公平Semaphore:
获得许可的顺序与线程启动的顺序有关:公平 (先启动的线程优先获得许可)
无关:非公平
fair=false非公平;true公平
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
同步处理
多个线程同步处理任务
private Semaphore semaphore = new Semaphore(3);
private Lock lock = new ReentrantLock();
public void test() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "准备阶段");
lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "打印:" + i);
}
System.out.println("结束阶段");
lock.unlock();
System.out.println(Thread.currentThread().getName() + "结束");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
Exchanger
Exchanger的主要作用可以使2个线程之间互相方便地进行通信
API
public V exchange(V x)
public V exchange(V x, long timeout, TimeUnit unit)
CountDownLatch和CyclicBarrier
倒计数CountDownLatch,倒计时等待CyclicBarrier
CountDownLatch
控制线程执行时机,即N个线程全部完成才能走下一步
给定计数器,CountDownLatch控制线程同步,计数器不为0则等待,为0则继续运行
CountDownLatch利用await()和countDown()等待,计数
注意:计数器无法重置,且计数为减一
API
CountDownLatch(构造方法传参初始化计数器count)
await()
public void await() 阻塞等待
await(long timeout, TimeUnit unit)
public boolean await(long timeout, TimeUnit unit) 阻塞等待timeout时间 单位unit
countDown
public void countDown() {
sync.releaseShared(1);
} 计数器减一
getCount 获取计数器当前数值
示例
public class CountDownLatchTest1 {
private CountDownLatch c = new CountDownLatch(3);
public void testMethod() {
try {
System.out.println(Thread.currentThread().getName() + "等待");
c.await();
System.out.println(Thread.currentThread().getName() + "继续运行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void downMethod() {
System.out.println("计数器执行 归队 还剩" + c.getCount());
c.countDown();
}
public static void main(String[] args) throws InterruptedException {
CountDownLatchTest1 count = new CountDownLatchTest1();
Thread[] threads = new Thread[3];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(count::testMethod);
threads[i].start();
}
Thread.sleep(2000);
count.downMethod();
count.downMethod();
count.downMethod();
}
}
打印
Thread-1等待
Thread-0等待
Thread-2等待
计数器执行 归队 还剩3
计数器执行 归队 还剩2
计数器执行 归队 还剩1
Thread-1继续运行
Thread-0继续运行
Thread-2继续运行
方法
await(long timeout, TimeUnit unit)
使线程在指定的最大时间单位内进入WAITING状态,超过这个时间自动唤醒,程序继续执行
getCount()
获取当前计数的值
CyclicBarrier
具有CountDownLatch的功能,同时可实现阶段性同步的功能,可以循环地实现线程要一起做任务的目标,而不像是CountDownLatch的计数器不能重置,只能执行一次
CountDownLatch多是等待一个或多个线程
CycliBarrier是同类等待,且加法计数
API
CyclicBarrier(int parties, Runnable barrierAction)
public CyclicBarrier(int parties, Runnable barrierAction)
parties互相等待的同行数量,barrierAction人齐之后执行的操作
CyclicBarrier()
public CyclicBarrier(int parties) {
this(parties, null);
}
getParties
await()
循环执行,每次等待 内置计数器加一,当计数器为parties则执行barrierAction并放行指定parties线程,重置计数器,周而复始
await(long timeout, TimeUnit unit)
public int await(long timeout, TimeUnit unit)
超时抛出异常TimeoutException
isBroken
public boolean isBroken()
查询是否破坏了同步点,即有线程被中断
reset
将同步点重置为其初始状态即getNumberWaiting归零。如果所有参与者目前都在同步点等待,则它们将返回,同时抛出一个BrokenBarrierException
getNumberWaiting
public int getNumberWaiting()
获取到达同步点的线程数量
示例
public class CyclicBarrierTest1 {
private CyclicBarrier c;
public CyclicBarrierTest1() {}
public CyclicBarrierTest1(CyclicBarrier c) {
super();
this.c = c;
}
public void testMethod() {
try {
Thread.sleep((int) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + "到了" + System.nanoTime());
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
CyclicBarrier cyclic = new CyclicBarrier(5, ()-> System.out.println("车满5人才开"));
CyclicBarrierTest1 test = new CyclicBarrierTest1(cyclic);
ExecutorService executor = Executors.newFixedThreadPool(25);
for (int i = 0; i < 25; i++) {
executor.execute(test::testMethod);
}
}
}
pool-1-thread-12到了450695198033783
pool-1-thread-23到了450695307647199
pool-1-thread-15到了450695328641933
pool-1-thread-21到了450695427387976
pool-1-thread-11到了450695431334132
车满5人才开
pool-1-thread-19到了450695464295332
pool-1-thread-4到了450695527091802
pool-1-thread-9到了450695579936013
pool-1-thread-13到了450695602917649
pool-1-thread-2到了450695714557561
车满5人才开
Phaser**
重点在于phase阶段数,parties参与线程数量
api
arriveAndAwaitAdvance()
可由arrive和awaitAdvance方法实现
类似于CountDownLatch类中的await方法,计数阻塞等待 计数值为构造方法传入的parties的值
public class PhaserTest1 {
private static Phaser p = new Phaser(3);
private static ExecutorService pool = Executors.newFixedThreadPool(3);
public static void test() {
System.out.println("start");
p.arriveAndAwaitAdvance();
System.out.println("synchronize");
p.arriveAndAwaitAdvance();
System.out.println("end");
}
public static void run() throws InterruptedException{
for (int i = 0; i < 3; i++) {
pool.execute(PhaserTest1::test);
Thread.sleep(2000);
}
}
}
运行结果:
start
start
start
此处parties计数满足3继续向下执行
synchronize
synchronize
synchronize
此处parties计数满足3继续向下执行
end
end
end
arriveAndAwaitAdvance有个缺陷,若有线程退出即计数器无法凑足parties数量的线程则一直阻塞,此时使用arriveAndDeregister,线程退出且parties数减一
arriveAndDeregister()
使当前线程退出,并且使parties值减1
注意:线程执行arrive的次数要与parties一致
System.out.println(p.getRegisteredParties());
Thread.sleep(5000);
p.arriveAndDeregister();
System.out.println(p.getRegisteredParties());
此时该线程执行之后,parties减一,之后的每个阶段阻塞的线程数减一
getPhase,onAdvance
getPhase方法获取已经到达的阻塞阶段数即arrive 满足parties线程数的阶段数
或者说重置parties的次数
onAdvance方法在通过新的阻塞阶段时被调用,即parties被重置计数时调用,类似于CyclicBarrier每次循环调用的一次方法
private static Phaser p = new Phaser(3){
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("onAdvance被调用");
return false;
// true,此时之后的线程不再等待,Phaser销毁
// false,此时Phaser继续工作
}
};
private static ExecutorService pool = Executors.newFixedThreadPool(3);
public static void testMethod2() {
String name = Thread.currentThread().getName();
System.out.println("start:" + name + System.currentTimeMillis());
p.arriveAndAwaitAdvance();
System.out.println("end:" + name + ";阶段:" + p.getPhase());
System.out.println("start:" + name + System.currentTimeMillis());
p.arriveAndAwaitAdvance();
System.out.println("end:" + name + ";阶段:" + p.getPhase());
}
onAdvance返回值false的结果
start:pool-1-thread-11567416155565
start:pool-1-thread-21567416155565
onAdvance被调用
end:pool-1-thread-1;阶段:1
start:pool-1-thread-11567416155566
end:pool-1-thread-2;阶段:1
start:pool-1-thread-21567416155566
onAdvance被调用
end:pool-1-thread-2;阶段:2
end:pool-1-thread-1;阶段:2
返回值true:此时只有第一个阶段有效
start:pool-1-thread-11567416236428
start:pool-1-thread-21567416236428
onAdvance被调用
end:pool-1-thread-1;阶段:-2147483647
end:pool-1-thread-2;阶段:-2147483647
start:pool-1-thread-11567416236429
start:pool-1-thread-21567416236429
end:pool-1-thread-1;阶段:-2147483647
end:pool-1-thread-2;阶段:-2147483647
getRegisteredParties,register
getRegisteredParties方法获得注册的parties的数量
register方法动态增加parties的值
bulkRegister
批量增加parties的值
getArrivedParties,getUnarrivedParties
getArrivedParties方法获得已经被使用的parties的值:到达的线程数
getUnarrivedParties方法获得尚未被使用的parties的值:还未到达的线程数
private static Phaser p = new Phaser(5);
public static void run() throws InterruptedException{
for (int i = 0; i < 3; i++) {
pool.execute(PhaserTest1::test);
Thread.sleep(2000);
}
System.out.println(p.getArrivedParties());
System.out.println(p.getUnarrivedParties());
}
打印:
3 // 已经使用
2 // 还未使用
arrive
该方法的作用是使parties的值加1,且不在阻塞阶段等待,直接向下继续执行,且Phaser类有计数重置功能,Phaser类在经过阻塞等待阶段后计数能被重置(onAdvance调用时)
注意,arrive不等待其他线程到达阻塞等待阶段,导致到达parties的值parties重置
public static void testMethodA() {
try {
// 阶段1起点:
String name = Thread.currentThread().getName();
System.out.println(name + ":start 起点" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println(phaser.getArrivedParties());
phaser.arriveAndAwaitAdvance();
System.out.println(name + ":start end");
// 阶段2中点:
System.out.println(name + ":middle 中点" + System.currentTimeMillis());
Thread.sleep(3000);
phaser.arriveAndAwaitAdvance();
System.out.println(name + ":middle end");
// 阶段3终点:
System.out.println(name + ":end 终点" + System.currentTimeMillis());
Thread.sleep(3000);
phaser.arriveAndAwaitAdvance();
System.out.println(name + ":end end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void testMethodB() {
String name = Thread.currentThread().getName();
System.out.println(name + ":start 起点" + System.currentTimeMillis());
phaser.arrive();
System.out.println(name + ":start end");
System.out.println(name + ":middle 中点" + System.currentTimeMillis());
System.out.println("arrive"+ phaser.getArrivedParties());
phaser.arrive();
System.out.println("arrive"+ phaser.getArrivedParties());
System.out.println(name + ":middle end");
System.out.println(name + ":end 终点" + System.currentTimeMillis());
phaser.arrive();
System.out.println("arrive"+ phaser.getArrivedParties());
System.out.println(name + ":end end");
}
private static Phaser phaser = new Phaser(3);
public static void runA() {
Thread a = new Thread(PhaserTest1::testMethodA);
a.setName("A");
a.start();
Thread b = new Thread(PhaserTest1::testMethodA);
b.setName("B");
b.start();
Thread c = new Thread(PhaserTest1::testMethodB);
c.setName("C");
c.start();
}
public static void main(String[] args) throws InterruptedException{
runA();
}
结果
A:start 起点1567419231407
B:start 起点1567419231407
C:start 起点1567419231407
C:start end
C:middle 中点1567419231407
arrive1
arrive2
C:middle end
C:end 终点1567419231407
arrive0
C:end end
0
0
awaitAdvance(int phase)
该方法的作用是:若传入参数phase值和当前getPhase方法返回值一样,则在阻塞阶段处等待,否则继续向下运行。类似旁观者
实际上是规定等待的阶段数,即线程同时到达阻塞点phase次则等待
arriveAndAwaitAdvance()相当于arrive加上awaitAdvance(0),awaitAdvance(1) 参数phase间隔n,n为1
注意:awaitAdvance(int phase)不参与parties计数的操作,仅判断阻塞
public static void test2() {
p2.arrive();
System.out.println("arrive 等待");
p2.awaitAdvance(0);
System.out.println("normal" + p2.getPhase());
p2.arrive();
System.out.println("arrive 等待");
p2.awaitAdvance(1);
System.out.println("normal" + p2.getPhase());
}
public static void test22(){
try {
Thread.sleep(2000);
p2.arriveAndAwaitAdvance();
System.out.println("await" + p2.getPhase());
Thread.sleep(2000);
p2.arriveAndAwaitAdvance();
System.out.println("await" + p2.getPhase());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void run22(){
Thread[] ts = new Thread[2];
ts[0] = new Thread(PhaserTest1::test2);
ts[0].start();
ts[1] = new Thread(PhaserTest1::test22);
ts[1].start();
}
结果:
arrive 等待
await1
normal1
arrive 等待
await2
normal2
awaitAdvanceInterruptibly
awaitAdvance(int)是不可中断的,线程调用interrupt不抛异常,不中断
awaitAdvanceInterruptibly(int)支持中断,会响应线程中断,会抛出interruptedException异常
awaitAdvanceInterruptibly(int,long,TimeUnit):在指定的阶段等待最大的单位时间,若在指定的时间内阶段不变,则出现异常,否则继续向下运行
即处理超时异常
forceTermination,isTerminated
forceTerminatiion方法使Phaser对象的阶段等待功能失效
isTerminated方法是判断Phaser对象是否已经呈销毁状态
注意:Phaser执行forceTermination方法时仅仅将阶段阻塞取消,线程继续执行后面的代码,并不抛出异常,而CyclicBarrier类的reset方法执行时会将抛出异常
控制运行时机
register注册使线程等待,arriveAndDeregister注销,使其他线程继续运行
Phaser特点
该类提供了动态增减parties计数,CyclicBarrier不行;可通过若干方法控制多个线程之间同步运行的效果,还可以实现针对某一线程取消同步运行的效果,且支持在指定阶段阻塞处等待,等待时支持中断或非中断等功能,使用java并发类对线程进行分组同步控制时,Phaser比CyclicBarrier类功能更强大
完美替代CyclicBarrier和CountDownLatch的功能
Executor与ThreadPoolExecutor
线程池的核心原理在于创建了一个高效率的线程池ThreadPool
Executor
java.util.concurrent.Executor
Executor接口是一种规范,声明
Executor类结构
Executor
--ExecutorService
----AbstractExecutorService
------DelegatedExecutorService
------ForkJoinPool
------ThreadPoolExecutor
----ScheduledExecutorService
------DelegatedScheduledExecutorService
------ScheduledThreadPoolExecutor
接口ExecutorService方法:
void shutdown()
List<Runnable> shutdownNow()
boolean isShutdown()
boolean isTerminated()
boolean awaitTermination(long timeout, TimeUnit unit)
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)
Future<?> submit(Runnable task)
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
Executors工厂创建线程池
Executors的方法:
固定线程数线程池
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
单一线程线程池
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
可伸缩线程线程池
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
本质上都是ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
newCachedThreadPool
本质上核心corePoolSize数为0,最大线程数maximumPoolSize为Integer.MAX_VALUE
Executors类的newCachedThreadPool()无参方法创建的是无界线程池,可进行线程自动回收,池中存放线程数最大值为Integer.MAX_VALUE
newCachedThreadPool(ThreadFactory):定制线程工厂
newFixedThreadPool
corePoolSize和maximumPoolSize相等
newFixedThreadPool(int):有界线程池,池中的数量可以指定,且线程数不能超过该指定数
newFixedThreadPool(int,ThreadFactory):定制线程工厂
newSingleThreadExecutor
corePoolSize和maximumPoolSize都为1
newSingleThreadExecutor():创建单一线程,可以实现阻塞队列的功能,实际上队列用到的是BlockingQueue workQueue
newSingleThreadExecutor(ThreadFactory):定制线程工厂
ThreadPoolExecutor自定义线程池
api
getActiveCount:取得有多少个线程正在执行任务
getPoolSize:获取当前线程池中有多少个线程,包括正在执行任务的线程和休眠的线程
自定义线程池,构造方法参数详解:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:池中所保存的线程数,包括空闲线程(即不回收而空闲),也就是核心池的大小
maximumPoolSize:池中允许的最大线程数,若超过指定时间(keepAliveTime)则进行回收,最低保持线程数为corePoolSize
keepAliveTime:当线程数量大于corePoolSize值时,在没有超过指定的时间内是不从线程池中将空闲线程删除的,若超过此时间单位,则删除
unit:keepAliveTime参数的时间单位
workQueue:执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable任务(待执行的任务数超过指定的最大线程数,则任务放入队列等待)
LinkedBlockingDeque
LinkedBlockingQueue
基于链表的阻塞队列
ArrayBlockingQueue
基于数组的阻塞队列实现
SynchronousQueue
没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素
使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界,避免线程拒绝执行操作
threadFactory:定制线程的信息,异常捕获;线程名称
handler:拒绝策略,线程数超过队列的长度
shutdown,shutdownNow
shutdown方法使当前未执行完的线程继续执行,而不再添加新的任务Task,且shutdown方法不会阻塞,調用shutdown方法后,主线程main马上结束,线程池会把池中的任务完成再停止
shotdownNow方法中断所有的任务Task,并且抛出InterruptedException异常,前提是在Runnable中使用if(Thread.currentThread().isInterrupted() == true)语句来判断当前线程的中断状态,而未执行的线程不再执行,即从执行队列中清除,若没有以上语句,则池中正在运行的线程直到执行完毕,而未执行的线程不再执行
if (Thread.currentThread().isInterrupted() == true) {
throw new InterruptedException();
}
当线程池调用shutdown()方法时,线程池的状态则立刻变成SHUTDOWN状态,此时不能再往线程池中添加任何任务,否则抛出RejectedExecutionException异常。但是,此时线程池不会立刻退出,直到线程池中的任务都已经处理完成,才会退出
而shutdownNow方法是使线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程(若有if判断则人为抛出异常),不再处理还在池队列中等待的任务,并且返回未执行的任务
List<Runnable> list = pool.shutdown();
isShutdown
该方法判断线程池是否已经关闭
isTerminated,isTerminating
一个正在执行的程序处于shutdown或shutdownNow之后处于正在终止但尚未完全终止的过程中,调用方法isTerminating则返回true。
若线程池关闭,即所有任务都已完成,则方法isTerminated返回true
awaitTermination
awaitTermination(long timeout, TimeUnit unit)方法:查看在指定的时间之间,线程池是否已经终止工作,即最多等待多少时间后去判断线程池是否已经终止工作
此方法与shutdown方法配合,且该方法会阻塞timeout时间
ThreadFactory
对线程池中创建的线程属性进行定制化,此时需要配置ThreadFactory线程工厰
public class TestThreadFactory implements ThreadFactory{
/**
* 线程编号保持原子性
*/
private final AtomicLong threadCounter;
/**
* newThread解耦
*/
private final ThreadFactory wrappedFactory;
/**
* 线程未捕获异常
*/
private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
/**
* 线程工厂名称前缀
*/
private final String namingPattern;
/**
* 优先级设置
*/
private final Integer priority;
/**
* 是否开启守护线程
*/
private final Boolean daemon;
private TestThreadFactory(final Builder builder) {
if (builder.wrappedFactory == null) {
wrappedFactory = Executors.defaultThreadFactory();
} else {
wrappedFactory = builder.wrappedFactory;
}
namingPattern = builder.namingPattern;
priority = builder.priority;
daemon = builder.daemon;
uncaughtExceptionHandler = builder.exceptionHandler;
threadCounter = new AtomicLong();
}
public final ThreadFactory getWrappedFactory() {
return wrappedFactory;
}
public final String getNamingPattern() {
return namingPattern;
}
public final Boolean getDaemonFlag() {
return daemon;
}
public final Integer getPriority() {
return priority;
}
public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler;
}
public long getThreadCount() {
return threadCounter.get();
}
@Override
public Thread newThread(final Runnable runnable) {
final Thread thread = getWrappedFactory().newThread(runnable);
initializeThread(thread);
return thread;
}
private void initializeThread(final Thread thread) {
if (getNamingPattern() != null) {
final Long count = Long.valueOf(threadCounter.incrementAndGet());
thread.setName(String.format(getNamingPattern(), count));
}
if (getUncaughtExceptionHandler() != null) {
thread.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
}
if (getPriority() != null) {
thread.setPriority(getPriority().intValue());
}
if (getDaemonFlag() != null) {
thread.setDaemon(getDaemonFlag().booleanValue());
}
}
public static class Builder {
private ThreadFactory wrappedFactory;
private Thread.UncaughtExceptionHandler exceptionHandler;
private String namingPattern;
private Integer priority;
private Boolean daemon;
public Builder wrappedFactory(final ThreadFactory factory) {
Validate.notNull(factory, "Wrapped ThreadFactory must not be null!");
wrappedFactory = factory;
return this;
}
public Builder namingPattern(final String pattern) {
Validate.notNull(pattern, "Naming pattern must not be null!");
namingPattern = pattern;
return this;
}
public Builder daemon(final boolean daemon) {
this.daemon = Boolean.valueOf(daemon);
return this;
}
public Builder priority(final int priority) {
this.priority = Integer.valueOf(priority);
return this;
}
public Builder uncaughtExceptionHandler(
final Thread.UncaughtExceptionHandler handler) {
Validate.notNull(handler, "Uncaught exception handler must not be null!");
exceptionHandler = handler;
return this;
}
public void reset() {
wrappedFactory = null;
exceptionHandler = null;
namingPattern = null;
priority = null;
daemon = null;
}
public TestThreadFactory build() {
final TestThreadFactory factory = new TestThreadFactory(this);
reset();
return factory;
}
}
}
RejectedExecutionHandler
setRejectedExecutionHandler和getRejectedExecutionHandler方法用于处理任务被拒绝的行为策略
实现RejectedExecutionHandler接口
实现public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {}
且可将被拒绝的任务日志化
allowsCoreThreadTimeOut
allowsCoreThreadTimeOut()和allowsCoreThreadTimeOut(boolean value)用于配置核心线程是否有超时的效果,即核心线程也会在keepAliveTime时间超时被回收
pool.allowsCoreThreadTimeOut(true)
pool.getPoolSize() //0
prestartCoreThread
prestartCoreThread方法每调用一次就创建一个核心线程,返回值boolean,该布尔值表示是否启动了
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
executor.prestartCoreThread() // true
executor.prestartCoreThread() // true
executor.prestartCoreThread() // false 此时核心线程已经全部启动过了 上限为2
prestartAllThreads方法的作用是启动全部核心线程,返回值是启动核心线程的数量
getCompletedTaskCount
getCompleteedTaskCount方法用于取得已经执行完成的任务数
常见阻塞队列的使用
ArrayBlockingQueue和LinkedBlockingDeque可以指定队列存储元素的多少
LinkedBlockingDeque不指定则默认容量Integer.MAX_VALUE
SynchronousQueue无缓存队列,不存储,要求max大于任务数
线程池的拒绝策略
当线程池中的资源被全部占用时,对于新添加的Task任务有不同的处理策略,默认情况下,ThreadExecutor类中有4种不同的处理方式:
- AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出RejectedExecutionException异常
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 5, TimeUnit.SECONDS, new ArrayBlockingQueue(1), new ThreadPoolExecutor.AbortPolicy())
- CallerRunsPolicy:当任务添加到线程池中被拒绝时,会使用调用线程池的Thread线程对象处理被拒绝的任务
此策略一般用线程调用线程池
new ThreadPoolExecutor.CallerRunsPolicy()
- DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中
- DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务
注意:以上策略是ThreadPoolExecutor的静态内部类
afterExecute,beforeExecute
在线程池ThreadPoolExecutor类中重写这两个方法可以对线程池中执行的线程对象实现监控
即在execute方法执行前执行beforeExecute,之后执行afterExecute
remove
remove(Runnable)方法可以删除尚未被执行的Runnable任务
只能针对execute执行的方法