Java 线程池的创建——7种方法

本文详细介绍了Java中通过Executors和ThreadPoolExecutor创建线程池的多种方式,包括newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool、newWorkStealingPool等,分析了它们的特点和适用场景,并探讨了线程池的优势和拒绝策略。同时,展示了如何手动创建线程池及其参数配置,以及不同的拒绝策略行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程池的创建分为两大类方法

  • 通过Executors自动创建
  • 通过ThreadPoolExecutor手动创建

Executors创建线程池的方法——6种

  1. newFixedThreadPool:创建一个固定大小的线程池
public class ThreadPool1 {
    public static void main(String[] args) {
        //1.创建一个大小为5的线程池
        ExecutorService threadPool= Executors.newFixedThreadPool(5);
        //2.使用线程池执行任务一
        for (int i=0;i<5;i++){
            //给线程池添加任务
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程名"+Thread.currentThread().getName()+"在执行任务1");
                }
            });
        }
        //2.使用线程池执行任务二
        for (int i=0;i<8;i++){
            //给线程池添加任务
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程名"+Thread.currentThread().getName()+"在执行任务2");
                }
            });
        }

    }
}

结果:
在这里插入图片描述

  1. newCachedThreadPool:带缓存的线程池,适用于短时间有大量任务的场景,但有可能会占用更多的资源;线程数量随任务量而定。
public class ThreadPool3 {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService service= Executors.newCachedThreadPool();
        //有50个任务
        for(int i=0;i<50;i++){
            int finalI = i;
            service.submit(()->{
                System.out.println(finalI +"线程名"+Thread.currentThread().getName());//线程名有多少个,CPU就创建了多少个线程
            });
        }
    }
}

结果:
执行了两次:一次有18个线程,一次有19个线程;线程的数量由cpu根据任务量而定。

  1. newSingleThreadExecuto:创建单个线程的线程池

创建单个线程的线程池?为啥不直接创个线程?

  • 线程池的优点:
  • 1.复用线程:不必频繁创建销毁线程
  • 2.也提供了任务队列和拒绝策略
public class ThreadPool4 {
    public static void main(String[] args) {
        ExecutorService service= Executors.newSingleThreadExecutor();
        for (int i=0;i<5;i++){
            int finalI = i;
            service.submit(()->{
                System.out.println(finalI +"线程名"+Thread.currentThread().getName());//CPU只创建了1个线程,名称始终一样
            });
        }
    }
}

结果:
在这里插入图片描述

  1. newSingleThreadScheduledExecutor:创建执行定时任务的单个线程的线程池
public class ThreadPool5 {
    public static void main(String[] args) {
        ScheduledExecutorService service= Executors.newSingleThreadScheduledExecutor();
        System.out.println("添加任务:"+ LocalDateTime.now());
        service.schedule(new Runnable() {

                @Override
                public void run() {
                    System.out.println("执行任务:"+LocalDateTime.now());
                }
            },3,TimeUnit.SECONDS);//推迟3秒执行任务
    }
}

结果:时间相差 3s
在这里插入图片描述

  1. newScheduledThreadPool:创建执行定时任务的线程池
/**
 * 创建执行定时任务的线程池
 */
public class ThreadPool6 {
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);//5个线程
        System.out.println("添加任务:" + LocalDateTime.now());
        //once(service);
        many(service);
    }
    /**
     * 执行一次的定时任务
     */
    public static void once(ScheduledExecutorService service) {
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务:"+ LocalDateTime.now());
            }
        },3, TimeUnit.SECONDS);//推迟3秒执行
    }
}

执行一次的定时任务 的结果:

在这里插入图片描述
当执行多次的定时任务——scheduleWithFixedDelay

//2.推迟3秒执行;上一次任务结束2s后,下一个任务开始执行
        service.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务:"+ LocalDateTime.now()+"线程名"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000*2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },3,2,TimeUnit.SECONDS);//间隔时间成了4s;因为线程休眠了2s

在这里插入图片描述
当执行多次的定时任务——scheduleAtFixedRate

//1.推迟3秒执行;上一次任务开始2s后,下一个任务开始执行
       service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务:"+ LocalDateTime.now()+"线程名"+Thread.currentThread().getName());
                try {
                    //1.间隔时间>执行时间;以间隔时间为准
                    Thread.sleep(100);
                    //2.执行时间>间隔时间;以执行时间为准
                    Thread.sleep(1000*3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },3,2,TimeUnit.SECONDS);

1.间隔时间2s>执行时间0.1s;以间隔时间为准
在这里插入图片描述

2.执行时间3s>间隔时间2s;以执行时间为准
在这里插入图片描述

  1. newWorkStealingPool:根据当前设备的配置自动生成线程池
public class ThreadPool7 {
    public static void main(String[] args) {
        ExecutorService service= Executors.newWorkStealingPool();
        for(int i=0;i<50;i++){
            int finalI = i;
            service.submit(()->{
                System.out.println(finalI +"线程名"+Thread.currentThread().getName());//线程名有多少个,CPU就创建了多少个线程
            });
        }
        //创建的为守护线程,JVM不会等待守护线程结束
        while (!service.isTerminated()){

        }
    }
}

根据自身电脑配置决定创建的线程数目

ThreadPoolExecutor——7.手动创建线程池

public class ThreadPool9 {
    public static void main(String[] args) {
        //线程工厂
        ThreadFactory factory=new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread=new Thread(r);

                return thread;
            }
        };
        //手动创建线程池
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(2), factory,
                //1.提示异常,拒绝执行多余的任务
               // new ThreadPoolExecutor.AbortPolicy()

                //2.忽略堵塞队列中最旧的任务
                //new ThreadPoolExecutor.DiscardOldestPolicy()

                //3.忽略最新的任务
                //new ThreadPoolExecutor.DiscardPolicy()

                //4.使用调用该线程池的线程来执行任务
                //new ThreadPoolExecutor.CallerRunsPolicy()

                //5.A自定义拒绝策略
                new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("拒绝策略");
            }
        }
        );
        //任务
        for (int i=0;i<7;i++){
            int finalI=i;
            threadPoolExecutor.submit(()->{
                try {
                    Thread.sleep(finalI*100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"任务名"+finalI);
            });
        }
        
    }
}

在这里插入图片描述
7种参数分别是:

  • 核心(最少)线程数

  • 最大线程数

  • 闲置可存活时间

  • 描述(闲置可存活时间)的单位

  • 任务队列

  • 线程工厂

  • 拒绝策略有5种:

             //1.提示异常,拒绝执行多余的任务
            // new ThreadPoolExecutor.AbortPolicy()
            
            //2.忽略堵塞队列中最旧的任务
             //new ThreadPoolExecutor.DiscardOldestPolicy()
    
             //3.忽略最新的任务
             //new ThreadPoolExecutor.DiscardPolicy()
    
             //4.使用调用该线程池的线程来执行任务
             //new ThreadPoolExecutor.CallerRunsPolicy()
    
             //5.自定义拒绝策略
             new RejectedExecutionHandler()
    
### 配置 HttpClient 的连接池和线程池 #### PoolingClientConnectionManager 设置 为了高效利用 HTTP 请求资源,`PoolingClientConnectionManager` 是用于管理多个并发请求的关键组件。通过设置 `setMaxTotal` 和 `setDefaultMaxPerRoute` 参数可以控制整个连接池的最大连接数以及每条路由的最大连接数量。 ```java PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(); connectionManager.setMaxTotal(200); // 整个连接池最大连接数 connectionManager.setDefaultMaxPerRoute(20); // 每个路由默认最大连接数 ``` 此配置有助于优化网络性能并减少延迟[^2]。 #### 创建 HttpClients 实例 由于 `HttpClient` 类本身是线程安全的,因此建议在整个应用程序生命周期内仅创建一个实例来处理所有的HTTP请求操作。 ```java CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .build(); ``` 这不仅提高了效率还减少了不必要的对象创建开销[^4]。 #### 结合线程池使用 当面对大量异步任务时,结合 Java 自带的 ExecutorService 来批量提交任务会更加合理有效。下面展示了一个简单的例子: ```java ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < taskCount; ++i) { final int index = i; executorService.submit(() -> { try { CloseableHttpResponse response = httpClient.execute(new HttpGet("http://example.com")); System.out.println(index + ": " + response.getStatusLine()); EntityUtils.consume(response.getEntity()); } catch (IOException e) { Thread.currentThread().interrupt(); // Handle exception properly in production code. } }); } executorService.shutdown(); try { if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)) { throw new RuntimeException("Tasks did not complete."); } } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } ``` 上述代码片段展示了如何在一个固定大小为10的工作线程池中执行一系列 GET 请求的任务。这种方式能够显著提升多IP查询场景下的整体响应速度,相比单一线程环境可缩短至六分之一的时间消耗[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值