多线程代码案例之线程池

作者简介: zoro-1,目前大二,正在学习Java,数据结构,javaee等

作者主页: zoro-1的主页

欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

创建线程池

java 复制代码
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类创建线程池

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

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

java 复制代码
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.创建一个构造方法,创建指定线程数,并让这些线程执行任务

2.有一个阻塞队列用来添加任务

3.创建一个submit方法添加新任务

java 复制代码
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);
                }
            });
        }
    }
}
                         今天的分享到这里就结束了,感谢大家支持
相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端