《java并发编程的艺术》线程池

好处:
1. 降低资源消耗
2. 提高响应速度
3. 提高线程的可管理性

处理流程

提交任务到线程池的处理流程:

graph LR
A[提交任务]-->B(核心线程池)
B-->C{判断核心线程池是否满}
C-->|满了| D{判断工作队列是否满了}
C-->|没满| E[创建新的工作线程]
D-->|满了| F{判断核心线程池是否满了}
D-->|没满| G[将任务存储到队列里]
F-->|满了| H[交给饱和策略处理]
F-->|没满| J[创建新线程执行工作]

ThreadPoolExecutor执行execute方法的流程和上述相似。(避免获取全局锁)
1. 如果当前运行的线程少于corePoolSize,创建新线程来执行任务(需要获取全局锁)否则,将任务加入BlockingQueue
2. 如果BlockingQueue满,创建新的线程处理任务
3. 如果创建新线程将使当前运行的线程超过maximumPoolSize,任务被拒绝,并调用RejectedExecutionHandler.rejectedExecution方法

线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,循环获取工作队列里的任务执行。

线程池的使用

创建:

new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
  • corePoolSize:线程池的基本大小
  • maximumPoolSize:线程池最大数量
  • keepAliveTime:线程活动保持时间。线程池工作线程空闲后保持存活的时间。
  • unit:线程活动保持时间的单位
  • workQueue:任务队列,用于保持等待执行的任务的阻塞队列。4种:ArrayBlockingQueue(基于数组结构的有界阻塞队列,FIFO),LinkedBlockingQueue(基于链表结果的有界阻塞队列),SynchronousQueue(一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作否则插入操作一直处于阻塞状态),PriorityBlockingQueue(具有优先级的无限阻塞队列).
  • threadFactory:设置线程的工厂,可以通过线程工厂给每个创建的线程设置更有意义的名字。
  • handler:饱和策略,队列和线程满了,线程池就处于饱和状态。4种处理提交新任务的策略:AbortPolicy(直接抛异常),CallerRunsPolicy(只用调用者所在线程运行任务),DiscardOldestPolicy(丢弃队列里最近的一个任务并执行当前任务),DiscardPolicy(不处理,直接丢弃)

向线程池提交任务,两个方法execute()和submit()
execute()方法用于提交不需要返回值的任务,无法判断任务是否被线程池执行成功。

threadsPool.execute(new Runnable(){
    @Override
    public void run(){

    });
}

submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过future的get()获取返回值,get()方法会阻塞当前线程直到任务完成,使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回。

Future<?> future = threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {

            }
        });
        try {
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

关闭线程池:
调用shutdown或shutdownNow方法关闭线程池。原理是遍历线程池的工作线程,逐个调用线程的interrupt方法中断线程。
shutdown将线程池状态设置为STOP状态,然后中断所有没有在执行任务的线程。
shutdownNow:首先将线程池状态设置为STOP状态,然后尝试停止所有正在执行或暂停任务的线程并返回等待执行任务的列表。

调用上述方法后,isShutDown方法就会返回true。当所有任务都关闭后,调用isTerminated方法才会返回true。

配置线程池,分析角度:
- 任务的性质:CPU密集型任务(尽可能小的线程),IO密集型任务(尽可能多的线程),混合型任务
- 任务的优先级(PriorityBlockingQueue):中,高,低
- 任务的执行时间:长,中,短
- 任务的依赖性(线程数设置的越大越好利用CPU):是否依赖其他系统资源,如数据库连接。

建议使用有界队列增加系统的稳定性和预警能力。

线程池的监控:
- taskCount:线程池需要执行的任务数量。
- completedTaskCount:线程池在运行过程中已经完成的任务数量,小于或等于taskCount.
- largestPoolSize:线程池里曾经创建过的最大线程数量。
- getPoolSize:线程池的线程数量
- getActiveCount:获取活动的线程数

猜你喜欢

转载自blog.csdn.net/saywhat_sayhello/article/details/81132430