多线程代码案例之线程池

作者简介: 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);
                }
            });
        }
    }
}
复制代码
                         今天的分享到这里就结束了,感谢大家支持
相关推荐
CV-杨帆10 小时前
AAAI 2026 大模型安全相关论文整理
安全
juniperhan10 小时前
Flink 系列第4篇:Flink 时间系统与 Timer 定时器实战精讲
java·大数据·数据仓库·flink
超级大只老咪10 小时前
一维度前缀和解题通用模板(java)
java·开发语言·算法
无限进步_11 小时前
【C++】重载、重写和重定义的区别详解
c语言·开发语言·c++·ide·windows·git·github
许杰小刀11 小时前
Python网络请求库,从 requests 到 httpx
开发语言·python·httpx
历程里程碑11 小时前
1 . Git本地操作:版本控制 跨平台协作 仓库核心
java·开发语言·数据结构·c++·git·gitee·github
2501_9481142411 小时前
Claude Sonnet 4.6 深度评测:性能逼近 Opus、成本打骨折,附接入方案与选型指南
大数据·网络·人工智能·安全·架构
hekung11 小时前
maven的lifecycle与idea的run
java·maven
阿维的博客日记11 小时前
为什么 ConcurrentHashMap 采用 synchronized 加锁而不采用ReentrantLock
java·juc
humors22111 小时前
一些安全类网站(不定期更新)
linux·网络·windows·安全·黑客·白帽