多线程代码案例之线程池

作者简介: 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);
                }
            });
        }
    }
}
复制代码
                         今天的分享到这里就结束了,感谢大家支持
相关推荐
FreeBuf_6 分钟前
最新研究揭示云端大语言模型防护机制的成效与缺陷
网络·安全·语言模型
_r0bin_2 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
zhang98800002 小时前
JavaScript 核心原理深度解析-不停留于表面的VUE等的使用!
开发语言·javascript·vue.js
硅的褶皱3 小时前
对比分析LinkedBlockingQueue和SynchronousQueue
java·并发编程
MoFe13 小时前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
季鸢3 小时前
Java设计模式之观察者模式详解
java·观察者模式·设计模式
Fanxt_Ja3 小时前
【JVM】三色标记法原理
java·开发语言·jvm·算法
蓝婷儿3 小时前
6个月Python学习计划 Day 15 - 函数式编程、高阶函数、生成器/迭代器
开发语言·python·学习
CYRUS_STUDIO3 小时前
FART 脱壳某大厂 App + CodeItem 修复 dex + 反编译还原源码
android·安全·逆向
love530love4 小时前
【笔记】在 MSYS2(MINGW64)中正确安装 Rust
运维·开发语言·人工智能·windows·笔记·python·rust