多线程代码案例之线程池

本文介绍了Java中线程池的创建方式,重点分析了ThreadPoolExecutor的四个参数含义,并讨论了线程池的执行流程和处理策略。同时,对比了Executors类提供的不同线程池创建方法及其应用场景。
摘要由CSDN通过智能技术生成

在这里插入图片描述

作者简介: zoro-1,目前大二,正在学习Java,数据结构,javaee等
作者主页: zoro-1的主页
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

创建线程池

public class PoolText {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(2);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务1 "+Thread.currentThread());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务2 "+Thread.currentThread());
            }
        });
    }
}

一共有两大种创建线程池的方式

ThreadPoolExcutor类创建线程池

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) 
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) 
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

以上四种方法都是大同小异,这里我们挑选参数最多的进行讲解

public ThreadPoolExecutor(
    // 线程池核心线程数
    int corePoolSize, 
    // 线程池最大数
    int maximumPoolSize, 
    // 空闲线程存活时间
    long keepAliveTime,  
    // 时间单位
    TimeUnit unit,
    // 线程池所使用的阻塞队列
    BlockingQueue<Runnable> workQueue,
    // 线程池创建线程使用的工厂
    ThreadFactory threadFactory,
    // 线程池对拒绝任务的处理策略
    RejectedExecutionHandler handler)
    }

将线程池比作一个公司,当这个公司不忙时是10个员工(corePoolSize),忙碌起来就需要招实习生,假设招来5个实习生(maximumPoolSize=5+10),当公司不忙时,实习生就空闲下来了,这时就要裁掉实习生,但是是当实习生空闲到一定时间才裁掉,假设实习生空闲10小时就要裁掉他们(keepAliveTime=10,unit=h)
而这里的阻塞队列负责的就是存任务,threadFactory就是将创建线程对象的任务交给工厂类(将工厂方法(使用普通方法将构造方法封装起来)放进类),而这里的handler就是当队列满的时候如何处理新的任务加进来的情况。

这里为什么要用阻塞队列?

阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。当队列中有任务时才唤醒对应线程从队列中取出消息进行执行。使得在线程不至于一直占用cpu资源。

处理决策

ThreadPoolExecutor是Java中的线程池实现类,它提供了四种处理策略:

  1. AbortPolicy(默认策略):当线程池无法容纳新的任务时,会抛出RejectedExecutionException异常。

  2. CallerRunsPolicy:当线程池无法容纳新的任务时,任务会退回给调用者执行,这样调用者就会阻塞。

  3. DiscardOldestPolicy:当线程池无法容纳新的任务时,会丢弃队列中最老的一个任务,然后尝试再次提交新任务。

  4. DiscardPolicy:当线程池无法容纳新的任务时,会直接丢弃任务,不做任何处理。

这些处理策略可以在创建ThreadPoolExecutor对象时通过参数设置。如果没有显式地指定,默认使用AbortPolicy策略。根据具体的业务需求,可以选择适合的处理策略。

Executors类创建线程池

  1. newFixedThreadPool(int nThreads):创建一个固定大小的线程池,该线程池中的线程数始终为nThreads。

  2. newCachedThreadPool():创建一个可缓存的线程池,该线程池中的线程数根据需要动态增加或减少,空闲线程会被保留60秒。

  3. newSingleThreadExecutor():创建一个只有一个线程的线程池,该线程池保证所有任务按照提交顺序依次执行。

  4. newScheduledThreadPool(int corePoolSize):创建一个定时任务线程池,该线程池可以定期执行任务或延迟执行任务。

这些方法返回的都是ExecutorService接口的实例,使用execute()方法来提交任务给线程池执行。

线程池的执行流程

在这里插入图片描述
线程池的执行流程:

1.当新加入一个任务时,先判断当前线程数是否大于核心线程数,如果结果为 false,则新建线程并执行任务;
2.如果结果为 true,则判断任务队列是否已满,如果结果为 false,则把任务添加到任务队列中等待线程执行
3.如果结果为 true,则判断当前线程数量是否超过最大线程数?如果结果为 false,则新建线程执行此任务
4.如果结果为 true,执行拒绝策略。

手搓一个线程池

过程:
1.创建一个构造方法,创建指定线程数,并让这些线程执行任务
2.有一个阻塞队列用来添加任务
3.创建一个submit方法添加新任务

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;

class MyPool{
    private List<Thread> list=new ArrayList<>();
    private BlockingQueue<Runnable> blockingDeque=new ArrayBlockingQueue<>(1000);
    //这里开启n个线程,这些线程不断的从阻塞队列的队首获取任务,一直执行
    public MyPool(int n) throws InterruptedException {
        for(int i=0;i<n;i++){
            Thread t=new Thread(()->{
                while (true){
                    Runnable runnable= null;
                    try {
                        runnable = blockingDeque.take();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    runnable.run();
                }
            });
            list.add(t);
            t.start();
        }
    }
    public  void submit(Runnable runnable) throws InterruptedException {
        blockingDeque.put(runnable);
    }
}
public class pool {
    public static void main(String[] args) throws InterruptedException {
        MyPool myPool=new MyPool(5);
        for(int i=0;i<1000;i++){
            int n=i;
            //因为这里是变量捕获语法变量是事实不可变的或final修饰这里可以采取每次都重新定义一个新的变量n(小技巧)
            myPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("当前线程是"+Thread.currentThread().getName()+"完成任务为"+n);
                }
            });
        }
    }
}
                         今天的分享到这里就结束了,感谢大家支持

在这里插入图片描述

  • 32
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zoro-1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值