Java线程池详解

使用线程池的优势:

①提高效率,创建好一定数量的线程放在线程池中,需要就取出来,比直接创建线程对象要快;
②减少创建和销毁线程的次数,线程可以被重复利用;
③提升系统响应速度,假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;

创建线程池的方式

newCacheTreadPool
创建一个可以缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,没回收的话就新建线程

线程池的最大核心线程为无限大,当执行第二个任务时第一个任务已经完成,则会复用执行第一个任务的线程;如果第一个线程任务还没有完成则会新建一个线程。

public static void main(String[] args)  {
    // 创建可缓存线程池
    ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        };
        newCachedThreadPool.execute(runnable);
    }
}

newFixedThread
创建一个定长的线程池,可控制最大并发数,超出的线程进行队列等待。

创建指定长度的线程池,任务超出当前线程池执行线程数量则会一直等待,直到运行。

public static void main(String[] args)  {
    // 创建定长线程池
    ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理
        newFixedThreadPool.execute(runnable);
    }
}

newScheduleThreadPool
可以创建定长的、支持定时任务,周期任务执行。

可以灵活配置延时、定时

public static void main(String[] args)  {
    // 创建支持定时线程池
    ScheduledExecutorService  newScheduledThreadPool = Executors.newScheduledThreadPool(2);
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理,延迟2秒后才开始执行线程池中的所有任务
        newScheduledThreadPool.schedule(runnable, 2, TimeUnit.SECONDS);
    }
}

newSingleExecutor
创建一个单线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

public static void main(String[] args)  {
    // 创建单线程-线程池,任务依次执行
    ExecutorService   newScheduledThreadPool = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理
        newScheduledThreadPool.execute(runnable);
    }
}

线程池的7种参数

通过 new ThreadPoolExecutor() 的写法创建线程池

ThreadPoolExecutor核心参数:
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
参数 含义 解释
corePoolSize 线程池中的核心线程数 核心线程生命周期无限,即使空闲也不会死亡。
maximumPoolSize 线程池中最大线程数 任务队列满了以后当有新任务进来则会增加一个线程来处理新任务(线程总数 < maximumPoolSize)
keepAliveTime 闲置超时时间 当线程数大于核心线程数时,经过keepAliveTime时间将会回收非核心线程
unit 超时时间的单位(时/分/秒等) TimeUnit.XXXX
workQueue 线程池中的任务队列 存放任务(Runnable)的容器
threadFactory 为线程池提供创建新线程的线程工厂 ( 默认:Executors.defaultThreadFactory() )
rejectedExecutionHandler 拒绝策略 新增一个任务到线程池,如果线程池任务队列超过最大值之后,并且已经开启到最大线程数时,默认为抛出ERROR异常(默认:new AbortPolicy() )

拒绝策略

// 当任务添加到线程池中被拒绝时,直接丢弃任务,并抛出RejectedExecutionException异常
AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
// 当任务添加到线程池中被拒绝时,丢弃被拒绝的任务,不抛异常
DiscardPolicy discardPolicy = new ThreadPoolExecutor.DiscardPolicy();
// 当任务添加到线程池中被拒绝时,丢弃任务队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
DiscardOldestPolicy discardOldestPolicy =  new ThreadPoolExecutor.DiscardOldestPolicy();
// 被拒绝任务的处理程序,直接在execute方法的调用线程中运行被拒绝的任务(就是被拒绝的任务,直接在主线程中运行,不再进入线程池。)
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();

工作流程

  • 线程在有任务的时候会创建核心的线程数corePoolSize。
  • 当线程满了(有任务但是线程被使用完)不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。
  • 如果队列满了,线程数达到最大线程数则会执行拒绝策略。
  • 当线程数大于核心线程数时,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。
# Java  线程 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×