Java并发编程之ThreadPool线程池基础部分-----什么是线程池,线程池架构,怎么使用

一.为什么要用线程池

线程池是一种多线程处理形式。

线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行


线程池的主要特点为: 线程复用;控制最大并发数;管理线程

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗
  2. 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

二.JDK1.8线程池架构

Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类

Executor:

public interface Executor {
    void execute(Runnable command);
}

Executor的官方定义是An object that executes submitted {@link Runnable} tasks 翻译过来就是:执行提交的任务(Runnable形式)


ExecutorService:

ExecutorService是Executor的子接口,它是Executor的扩展,能提供管理终止的方法(shutdown),以及可以生成Future对象以跟踪一个或多个异步任务的进度的方法
在这里插入图片描述

ThreadPoolExecutor:

ThreadPoolExecutor是线程池类,它提供几种构造函数让我们来创建线程池。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

线程池的参数非常重要,之后会有文章讲。


Executors:

Executors 工具类提供了四种不同的线程池来帮助我们创建不同需求的线程池,其实质也是调用ThreadPoolExecutor的构造方法。


三.代码示例:三种线程池

应用场景:银行有n个柜台,有10个顾客办理业务


public static void main(String[] args) {

        //1.newFixedThreadPool 固定个数线程池
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);

        //2.newSingleThreadExecutor 一池一线程
        //ExecutorService threadPool = Executors.newSingleThreadExecutor();

        //3.newCachedThreadPool 可扩容 有伸缩性 遇强则强
        //ExecutorService threadPool = Executors.newCachedThreadPool();

        try {

            for (int i = 1; i <= 10 ; i++) { //模拟10个顾客,execute传入参数是Runnable函数式接口

                threadPool.execute(()->{

                    System.out.println(Thread.currentThread().getName()+"\t办理业务");

                }); 

                //暂停400ms
                try { TimeUnit.MILLISECONDS.sleep(400); }catch (Exception e){ e.printStackTrace(); }

            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }


    }

首先我们创建线程池,这里用的是Executors提供的方法,其次我们用循环模拟10个任务,让线程池的线程来执行,最后在finally语句块调用shutdown关闭


1.Executors.newFixedThreadPool(int n)

执行长期任务性能好,创建一个线程池,一池有N个固定的线程,有固定线程数的线程。可以通过将第一个语句注释去掉运行看看结果:

pool-1-thread-1	办理业务
pool-1-thread-2	办理业务
pool-1-thread-3	办理业务
pool-1-thread-4	办理业务
pool-1-thread-5	办理业务
pool-1-thread-1	办理业务
pool-1-thread-2	办理业务
pool-1-thread-3	办理业务
pool-1-thread-4	办理业务
pool-1-thread-5	办理业务

Process finished with exit code 0

发现首先满足了我们的需求,其次分布很均匀,这是因为我们用TimeUnit睡了一段时间,否则就会比较混乱。


2.newSingleThreadExecutor

一个任务一个任务的执行,一池一线程 这相当于只有一个柜台能办理业务

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=55234:D:\idea\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\李肇京\IdeaProjects\JUC\out\production\JUC" JUC_01_SellTicket.ExecutorDemo.MyThreadPoolDemo
pool-1-thread-1	办理业务
pool-1-thread-1	办理业务
pool-1-thread-1	办理业务
pool-1-thread-1	办理业务
pool-1-thread-1	办理业务
pool-1-thread-1	办理业务

3.newCachedThreadPool

执行很多短期异步任务,线程池根据需要创建新线程,但在先前构建的线程可用时将重用它们。可扩容,遇强则强

  • 此时,如果我们把暂停线程的语句加上,你会发现情况跟2一样了,一直是一个线程来处理我们的任务,这是因为线程池认为当前情况下不需要多个线程处理
  • 如果把暂停语句去掉,或者把任务数增大,线程池会自动扩容,这时就会有多个线程处理我们的任务。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章