java并发包笔记一

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执行的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值