乐趣区

关于java:线程池基本介绍

线程池的创立

线程池的创立调用上面构造函数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
  • corePoolSize:线程池外围线程数最大值
  • maximumPoolSize:线程池最大线程数大小
  • keepAliveTime:线程池中非核心线程闲暇的存活工夫大小
  • unit:线程闲暇存活工夫单位
  • workQueue:寄存工作的阻塞队列
  • threadFactory:用于设置创立线程的工厂,能够给创立的线程设置有意义的名字,可不便排查问题。
  • handler:线程池的饱和策略事件,次要有四种类型。

工作执行

线程池执行流程,即对应execute()办法:提交一个工作,线程池里存活的外围线程池数小于线程数corePoolSize时,线程池会创立一个外围线程去解决提交的工作。如果线程池外围线程数已满,即线程池数曾经等于corePoolSize,一个新提交的工作,会被放进工作队列workQueue排队期待执行。当线程池外面存活的线程数曾经等于corePoolSize了,并且工作队列workQueue也满了,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没达到,创立一个非核心线程执行提交的工作。如果以后的线程数达到了maximumPoolSize,还有新的工作过去的话,间接采纳回绝策略解决。

四种回绝策略

  • AbortPolicy(抛出一个异样,默认的)
  • DiscardPolicy(间接抛弃工作)
  • DiscardOldestPolicy(抛弃队列里最老的工作,将以后这个工作持续提交给线程池)
  • CallerRunsPolicy(交给线程池调用所在的线程进行解决)

线程池异样解决

在应用线程池解决工作的时候,工作代码可能抛出RuntimeException,抛出异样后,线程池可能捕捉它,也可能创立一个新的线程来代替异样线程,咱们可能无奈感知工作呈现了异样,因而咱们须要思考线程池异常情况。

线程池的工作队列

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • DelayQueue
  • PriorityBlockingQueue
  • SynchronousQueue

ArrayBlockingQueue
ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序

LinkedBlockingQueue
LinkedBlockingQueue(可设置容量队列)基于链表构造的阻塞队列,按FIFO排序工作,容量能够进行抉择设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer的MAX_VALUE,吞吐量通常要高于ArrayBlockingQueue,newFIxedThreadPool线程池应用了这个队列。

DelayQueue
DelayQueue(提早队列)是一个工作定时周期的提早执行的队列。依据指定的执行工夫从小到大排序,否则依据插入到队列的先后排序,newScheduledThreadPool线程池应用了这个队列。

PriorityBlockingQueue
PriorityBlockingQueue(优先级队列)是具备优先级的无界阻塞队列

SynchronousQueue
SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入擦欧洲哦必须等到另一个线程调用移除操作,否则插入操作始终处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,newCachedThreadPool线程池应用了这个队列

几种罕用的线程池

  • newFixedThreadPool(固定数目线程的线程池)
  • newCachedThreadPool(可缓存线程的线程池)
  • newSingleThreadExecutor(单线程的线程池)
  • newScheduledThreadPool(定时及周期执行的线程池)

newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory){
    return new ThreadPoolExecutor(nThreads,nThreads,TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory);

线程池特点
外围线程数和最大线程数大小一样
没有所谓的非闲暇工夫,即keepAliveTime为0
阻塞队列为无界队列LinkedBlockingQueue

解决逻辑
如果线程数少于外围线程,创立外围线程执行工作
如果线程数等于外围线程,把工作增加到LinkedBlockingQueue阻塞队列
如果线程执行完工作,去阻塞队列取工作,继续执行。

例子

ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0;i<Integer.MAX_VALUE;i++){
    executor.execute(()->{
        try{
            Thread.sleep(10000);
        }catch(InterruptedException e){
        }
    }                                                   
}

应用无界队列的线程池会导致内存飙升,newFixedThreadPool应用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个工作后,工作的执行工夫比拟长(比方,下面demo设置了10秒),会导致队列的工作越积越多,导致机器内存应用不停飙升,最终导致OOM。newFixedThreadPool实用于解决CPU密集型的工作,确保CPU在长期被工作线程应用的状况下,尽可能少的调配线程,即实用执行长期的工作。

newCachedThreadPool

public static ExecutorService newCachedThreadPool(ThreadFactory threadfactory{
    return new ThreadPoolExecutor(0,INteger.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);
}

线程池特点
外围线程数为0
最大线程数为Integer。MAX_VALUE
阻塞队列是SynchronousQueue
非核心线程闲暇存活工夫为60秒

当提交工作的速度大于解决工作的速度时,每次提交一个工作,就必然会创立一个线程。极其状况下会创立过多的线程,耗尽CPU和内存资源。
因为闲暇60秒的线程会被终止,长时间放弃闲暇的CachedThreadPool不会占用任何资源。

解决逻辑
因为没有外围线程,所有工作间接加到SynchronousQueue队列
判断是否有闲暇线程,如果有,就去取出工作执行
如果没有闲暇线程,就新建一个线程执行
执行完工作的线程,还能够存活60秒,如果在这期间,接到工作,能够持续活下去;否则,被销毁。

例子

ExecutorService executor = Executors.newCachedThreadPool();
for(int i = 0;i<5;i++){
    executor.execute(()->{
    System.out.println(Thread.currentThread().getName()+"正在执行");
});

应用场景
用于并发执行大量短期的小工作

newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFActory){
    return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory));
}

线程池特点
外围线程数为1
最大线程数也为1
阻塞队列是LinkedBlockingQueue
keepAliveTime为0

解决逻辑
线程池是否有一条线程在,如果没有,新建线程执行工作。如果有,将工作加到阻塞队列。
以后的惟一线程,从队列取工作,执行完一个,再持续取,一个人(一条线程)披星戴月地干活。

ExecutorService executor = Executors.newSingleThreadExecutor();
for(int i =0 ;i<5;i++){
    executor.execute(()->{
    System.out.println(Thread.currentThread().getName()+"正在执行");
    });
}

应用场景
实用于串行执行工作的场景,一个工作一个工作地执行

newScheduledThreadPool

public ScheduledThreadPoolExecutor(int corePoolSize){
    super(corePoolSize,Integer.MAX_VALUE,0,NANOSECONDS,new DelayedWorkQueue());
}

线程池特点
最大线程数为Integer.MAX_VALUE
阻塞队列是DelayedWorkQueue
keepAliveTime为0
scheduleAtFixedRate():按某种速率周期执行
scheduleWithFixedDelay():在某个提早后执行

解决逻辑
线程池中的线程从DelayQueue中取工作,线程从delayQueue中获取time大于等于以后工夫的task
执行完后批改这个task的time为下次被执行的工夫,这个task放回DelayQueue队列中

ScheduleExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    scheduleExecutorService.scheduleWithFixeddelay(()->{
    System.out.println("current Time"+System.currentTimeMillis());
    System.out.println(Thread.currentThread().getName()+"正在执行");
    },1,3,TimeUnit.SECONDS);
    scheduledExecutorService.scheduleAtFixedRate(()->{
            System.out.println("current Time" + System.currentTimeMillis());
            System.out.println(Thread.currentThread().getName()+"正在执行");
        }, 1, 3, TimeUnit.SECONDS);

应用场景
周期性执行工作的场景,须要限度线程数量的场景

线程池状态

线程池有这几个状态:RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED

private static final int RUNNING = -1<<COUNT_BITS;
private static final int SHUTDOWN = 0<<COUNT_BITS;
private static final int STOP = 1<<COUNT_BITS;
private static final int TIDYING = 2<<COUNT_BITS;
private static final int TERMINATED = 3<<COUNT_BITS;

RUNNING
该状态的线程池会接管新工作,并解决阻塞队列中的工作;
调用线程池的shutdown()办法。能够切换到SHUTDOWN状态
调用线程池的shutdownNow()办法。能够切换到STOP状态

SHUTDOWN
该状态的线程池不会接管新工作,但会解决阻塞队列中的工作
队列为空,并且线程池中执行的工作也为空,进入TIDYING状态

STOP
该状态的线程不会接管新工作,也不会解决阻塞队列中的工作,而且会中断正在运行的工作;
线程池中执行的工作为空,进入TIDYING状态

TIDYING
该状态表明所有的工作曾经运行终止,记录的工作数量为0
terminated()执行结束,进入TERMINATED状态

TERMINATED
该状态示意线程池彻底终止

退出移动版