简单线程池的实现

线程池的实现

Java中的线程池-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/2301_79985750/article/details/143712343

这篇文章中讲述了Java中线程池的一些相关概念,这篇文章用代码实现简单的线程池。

1.固定线程池大小

        阻塞队列和线程池是需要实现的两个基本组成部分。任务在被调度后首先进入阻塞队列,它负责暂存待执行的任务,提供了线程安全的任务存储机制。线程池中包含一定数量的线程,从阻塞队列中获取任务并执行。因此就可以得到简单的线程池实实现

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;


class MyThreadPool {
    // 阻塞队列
    private BlockingQueue<Runnable> queue = null;
    public MyThreadPool(int n) {
        // ArrayBlockingQueue基于数组结构的有界阻塞队列
        queue = new ArrayBlockingQueue<>(1000);

        // 创建 N 个线程
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(()->{
                try {
                    while(true) {
                        Runnable task = queue.take();
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }
    // 任务提交给线程池
    public void submit(Runnable task) throws InterruptedException {
        queue.put(task);
    }
}

2.核心线程+非核心线程的实现

        任务的存在促进了线程的创建,因为涉及到了非核心的线程创建,为了减少代码的冗余,将任务进行适当的封装以供线程池的使用,因此将增加单个任务的代码进行封装,如下:

private void addWorker() {
        if (currentThreadCount.get() >= maximumSize){
            return;
        }
        // 增加线程计数
        currentThreadCount.incrementAndGet();
        // 创建并启动工作线程
        Thread worker = new Thread(() -> {
            try {
                while (isRunning || !queue.isEmpty()) {
                    Runnable task = queue.take();
                    task.run();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 减少线程计数
                currentThreadCount.decrementAndGet();
            }
        });
        worker.start();
    }

原子类型的currentThreadCount: 

  1. 为了限制线程池的大小,当currentThreadCount.get()达到了最大线程数,则不会在创建线程,从而避免了资源的过度消耗。
  2. 保证了线程安全,当线程增加和减少时,incrementAndGet()和decrementAndGet()保证了操作的原子性。
  3. 控制生命周期,(!isRunning && !queue.isEmpty())是退出条件,线程为没有运行而且阻塞队列没有任务,那么就进行退出,调用decrementAndGet()减少线程计数,可以正确的管理线程的状态。

初始化状态:

 public MyThreadPool2(int corePool,int maxPool,int queueSize) {
        this.corePoolSize = corePool;
        this.maximumSize = maxPool;
        this.queue = new ArrayBlockingQueue<>(queueSize);
        // 初始化核心线程
        init();
    }

    private void init() {
        for (int i = 0; i < corePoolSize; i++) {
            addWorker();
        }
    }

在构造方法 MyThreadPool2 中,设置了线程池的一些参数,包括核心线程数(corePool)、最大线程数 (maxPool) 以及任务队列的容量(queueSize)。通过调用 init 方法,初始化了指定数量的核心线程,确保线程池在创建之初就具备了一定的并发处理能力。

接下来去实现执行(execute)方法:这里要实现增加非核心线程以及将任务放到队列这两个任务。代码以及运行情况如下:

public void execute(Runnable task) throws InterruptedException {
       if (currentThreadCount.get() < maximumSize && queue.remainingCapacity() == 0) {
       // 如果剩余容量小于某个阈值,且当前线程数未达到最大值,则创建新线程
          addWorker();
       }
        // 将任务放入队列
        queue.put(task);
    }

 发现了什么,没有退出机制!!!

  • 由于没有退出机制,一旦线程数量达到maxinumSize,即使之后任务量减少,这些线程也不会销毁,导致线程资源被一直占用。
  • 如果使用的无界队列,那么queue.remainingCapacity() == 0永远不会为真,因此永远不会创建超过核心线程数的线程。
  • 这里queue.remainingCapacity() == 0意味着队列满才会创建新线程,可能导致任务队列等待时间过长,尤其是当任务处理速度跟不上提交速度情况下。由于这里线程数量少,这个在这里不做讨论

我们可以自定义退出机制,当队列满而且线程池已经达到最大线程数,抛出异常

throw new ThreadPoolException("队列已满且线程池已经达到最大线程数: " + maximumSize);

代码如下:

if (queue.remainingCapacity() == 0) {
            if(currentThreadCount.get() < maximumSize) {
                addWorker();
            }
            else {
                throw new ThreadPoolException("队列已满且线程池已经达到最大线程数: " + maximumSize);
            }
        }


try {
                pool2.execute(() -> {
                    System.out.println("执行的任务 " + id + " 在线程 " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(600);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    System.out.println("任务 " + id + " 完成");
                });
            } catch (InterruptedException | ThreadPoolException e) {
                System.err.println("任务 " + id + " 执行失败: " + e.getMessage());
            }

queue.remainingCapacity() == 0的情况下,检测当前线程的数量是否小于线程池最大线程个数,如果没有达到最大限制,可以增加一个新的工作线程,以便可以处理新来的任务,而不是将任务放到队列中等待。因为此时队列满了,无法存新的任务了。

如果不满足queue.remainingCapacity() == 0,即使队列有剩余空间来容纳新的任务,也没有必要立即添加新的线程,因为可以直接添加到队列中,等待现有的线程去处理。这样子可以避免创建过多线程,因为创建过多线程可能导致上下文切换消耗过大,降低系统性能,而且线程的数量有上限,可以防止系统资源耗尽。

如果队列满,而且当前线程达到最大值,说明线程池无法接受新的任务而且不能创建新的新的线程进行处理,那么这时抛出异常,表示系统无法处理更多的任务。

结果如下:

 至此,一个简单的线程池代码实现完毕:

import java.util.concurrent.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;


// 固定大小
class MyThreadPool1 {
    // 阻塞队列
    private BlockingQueue<Runnable> queue = null;
    public MyThreadPool1(int n) {
        // ArrayBlockingQueue基于数组结构的有界阻塞队列
        queue = new ArrayBlockingQueue<>(1000);

        // 创建 N 个线程
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(()->{
                try {
                    while(true) {
                        Runnable task = queue.take();
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }
    // 任务提交给线程池
    public void submit(Runnable task) throws InterruptedException {
        queue.put(task);
    }
}



class MyThreadPool2 {
    // 阻塞队列
    private BlockingQueue<Runnable> queue = null;
    // 最大容量
    private int QueueCapacity = 0;
    // 核心线程数
    private int corePoolSize = 0;
    // 最大线程数
    private int maximumSize = 0;
    // 当前线程数
    private final AtomicInteger currentThreadCount = new AtomicInteger(0);
    // 线程池是否正在运行
    private volatile boolean isRunning = true;

    public MyThreadPool2(int corePool,int maxPool,int queueSize) {
        this.corePoolSize = corePool;
        this.maximumSize = maxPool;
        this.queue = new ArrayBlockingQueue<>(queueSize);
        // 初始化核心线程
        init();
    }

    private void init() {
        for (int i = 0; i < corePoolSize; i++) {
            addWorker();
        }
    }

    private void addWorker() {
        if (currentThreadCount.get() >= maximumSize){
            return;
        }
        // 增加线程计数
        currentThreadCount.incrementAndGet();
        // 创建并启动工作线程
        Thread worker = new Thread(() -> {
            try {
                while (isRunning || !queue.isEmpty()) {
                    Runnable task = queue.take();
                    task.run();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 减少线程计数
                currentThreadCount.decrementAndGet();
            }
        });
        worker.start();
    }
    public void execute(Runnable task) throws InterruptedException, ThreadPoolException {

//        if (currentThreadCount.get() < maximumSize && queue.remainingCapacity() == 0) {
//            // 如果剩余容量小于某个阈值,且当前线程数未达到最大值,则创建新线程
//            addWorker();
//        }


//        if (queue.remainingCapacity() == 0) {
//            System.out.println("队列满了。。。。。。。。。。。");
//            if (currentThreadCount.get() < maximumSize) {
//                System.out.println("增添任务增加线程");
//                addWorker();
//            } else {
//                System.out.println("抛出 异常。。。。。。。。。。。。");
//                // throw new ThreadPoolException("队列已满且线程池已经达到最大线程数: " + maximumSize);
//            }
//        }else {
//            System.out.println("队列剩余容量:"+queue.remainingCapacity());
//        }



        if (queue.remainingCapacity() == 0) {
            if(currentThreadCount.get() < maximumSize) {
                addWorker();
            }
            else {
                throw new ThreadPoolException("队列已满且线程池已经达到最大线程数: " + maximumSize);
            }
        }

        // 将任务放入队列
        queue.put(task);
        // System.out.println("队列加元素了。。。。。。。。。。。。");
    }


}


public class Test {
    public static void main(String[] args) throws InterruptedException {
//        MyThreadPool1 pool = new MyThreadPool1(10);

        MyThreadPool2 pool2 = new MyThreadPool2(2,3,4);

        for (int i = 0; i < 10; i++) {
            int id = i;

//            pool2.execute(() -> {
//                System.out.println("执行的任务 " + id + " 在线程 " + Thread.currentThread().getName());
//                try {
//                    Thread.sleep(2000);
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                }
//                System.out.println("任务 " + id + " 完成");
//            });

//            pool.submit(()->{
//                System.out.println(Thread.currentThread().getName() + " id = " + id);
//            });

            try {
                pool2.execute(() -> {
                    System.out.println("执行的任务 " + id + " 在线程 " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(600);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    System.out.println("任务 " + id + " 完成");
                });
            } catch (InterruptedException | ThreadPoolException e) {
                System.err.println("任务 " + id + " 执行失败: " + e.getMessage());
            }

        }
        Thread.sleep(10000); // 等待足够的时间让所有任务完成
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值