如何自定义一个线程池?

首先明白下线程池的作用是什么?

线程池就是创建一批线程,通常我们想使用一个线程需要经历的过程有new、runnable、running、blocked、dead(仅对于操作系统而言),这是使用单个线程,但是使用多个呢?或者我频繁的使用线程?是不是都要经历这些过程
比如我现在要使用一个线程,新建---使用---使用完关闭线程,下次再使用时,在新建---使用----使用完再关闭,但实际上我们真正使用的仅仅只是runnable、running、block这几个阶段,剩下的都是新建和销毁,如果我们大量使用或者频繁使用线程,对于new和dead这两个过程来讲,完全是在浪费系统资源和时间
所以,线程池诞生了,池化思想主要来源于享元模式,线程池就是创建一定数量的线程,让他们时刻保持可用状态,如果有任务需要处理,直接调用,这样就避免了new和dead这种多余的操作;

需要什么?

  1. 线程池(消费者):用来存储创建好的线程

//线程池类
class ThreadPool {
 // 任务队列
 private BlockingQueue<Runnable> taskQueue;
 
 // 线程集合
 private HashSet<Worker> workers = new HashSet<>();
 
 // 核心线程数
 private int coreSize;
 
 // 获取任务时的超时时间
 private long timeout;
 
 private TimeUnit timeUnit;
 
 private RejectPolicy<Runnable> rejectPolicy;

 public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit, 
     int queueCapcity, RejectPolicy<Runnable> rejectPolicy) {
     this.coreSize = coreSize;
     this.timeout = timeout;
     this.timeUnit = timeUnit;
     this.taskQueue = new BlockingQueue<>(queueCapcity);
     this.rejectPolicy = rejectPolicy;
 }

// 执行任务
 public void execute(Runnable task) {
     synchronized (workers) {
      // 当任务数没有超过 coreSize 时,直接交给 worker 对象执行
     if(workers.size() < coreSize) {
         Worker worker = new Worker(task);
         log.debug("新增 worker{}, {}", worker, task);
         workers.add(worker);//将线程加入到工作队列中去
         worker.start();
     } else {// 如果任务数超过 coreSize 时,加入任务队列暂存
        // taskQueue.put(task);//死等方法
         // 1) 死等
         // 2) 带超时等待
         // 3) 让调用者放弃任务执行
         // 4) 让调用者抛出异常
         // 5) 让调用者自己执行任务
         taskQueue.tryPut(rejectPolicy, task);//通过策略模式来完成拒绝策略的不同实现
         }
     }
 }

    //将线程包装成worker类
    class Worker extends Thread{
         private Runnable task;

         public Worker(Runnable task) {
         this.task = task;
         }

         @Override
         public void run() {
             // 执行任务
             // 1) 当 task 不为空,执行任务
             // 2) 当 task 执行完毕,再接着从任务队列获取任务并执行
            // while(task != null || (task = taskQueue.take()) != null) {//没有超时时间的方法
                 while(task != null || (task = taskQueue.poll(timeout, timeUnit)) != null)//有超时时间的方法 {
                 try {
                     log.debug("正在执行...{}", task);
                     task.run();
                 } catch (Exception e) {
                     e.printStackTrace();
                 } finally {
                     task = null;
                 }
             }
             synchronized (workers) {
                 log.debug("worker 被移除{}", this);
                 workers.remove(this);
             }
         }
     }
}
  1. 阻塞队列(blockQueue):用来平衡生产者与消费者之间的桥梁

//阻塞队列
class BlockingQueue<T> {
 // 1. 任务队列(桥梁作用,平衡消费者与生产者之间的工作能力)
 private Deque<T> queue = new ArrayDeque<>();

 // 2. 锁(保护线程安全,用于队列头(多线程消费时)和队列尾(多线程生产时))
 private ReentrantLock lock = new ReentrantLock();
 
 // 3. 生产者条件变量(当队列满了之后,生产者线程需要等待,直到消费者将队列消费不满时,才被唤醒)
 private Condition fullWaitSet = lock.newCondition();
 
 // 4. 消费者条件变量(当队列空了后,消费者线程需要等待,直到重新生产出任务后方可被唤醒)
 private Condition emptyWaitSet = lock.newCondition();
 
 // 5. 容量(阻塞队列的容量)
 private int capcity;
 
 public BlockingQueue(int capcity) {
 this.capcity = capcity;
 }
 
 // 带超时阻塞获取(增加超时时间,防止无休止等待)
 public T poll(long timeout, TimeUnit unit) {
     lock.lock();
         try {
         // 将 timeout 统一转换为 纳秒
         long nanos = unit.toNanos(timeout);
         while (queue.isEmpty()) {
             try {
                 if (nanos <= 0) {
                 return null;
                 }
                 // 返回值是剩余时间
                 nanos = emptyWaitSet.awaitNanos(nanos);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         T t = queue.removeFirst();
         fullWaitSet.signal();
         return t;
     } finally {
         lock.unlock();
     }
 }

 // 阻塞获取
 public T take() {
     lock.lock();
     try {
         while (queue.isEmpty()) {//如果阻塞队列为空,那么线程阻塞
             try {
                 emptyWaitSet.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         T t = queue.removeFirst();//线程被唤醒后执行完任务后从阻塞队列中移除任务
         fullWaitSet.signal();//消费完任务后唤醒阻塞的生产线程进行任务生产
         return t;
     } finally {
         lock.unlock();
     }
 }

 // 阻塞添加
 public void put(T task) {
     lock.lock();
     try {
         while (queue.size() == capcity) {
             try {
                 log.debug("等待加入任务队列 {} ...", task);
                 fullWaitSet.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         log.debug("加入任务队列 {}", task);
         queue.addLast(task);//将任务添加进阻塞队列中
         emptyWaitSet.signal();//添加完新元素后唤醒消费者线程
     } finally {
         lock.unlock();
     }
 }

 // 带超时时间阻塞添加
 public boolean offer(T task, long timeout, TimeUnit timeUnit) {
     lock.lock();
     try {
         long nanos = timeUnit.toNanos(timeout);
         while (queue.size() == capcity) {
             try {
             if(nanos <= 0) {
                 return false;
             }
             log.debug("等待加入任务队列 {} ...", task);
             nanos = fullWaitSet.awaitNanos(nanos);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         log.debug("加入任务队列 {}", task);
         queue.addLast(task);
         emptyWaitSet.signal();
         return true;
     } finally {
         lock.unlock();
     }
 }
 //获取阻塞队列大小
 public int size() {
     lock.lock();
     try {
         return queue.size();
     } finally {
         lock.unlock();
     }
 }

 public void tryPut(RejectPolicy<T> rejectPolicy, T task) {
     lock.lock();
     try {
         // 判断队列是否满       
         if(queue.size() == capcity) {
             rejectPolicy.reject(this, task);
         } else { // 有空闲        
             log.debug("加入任务队列 {}", task);
             queue.addLast(task);
             emptyWaitSet.signal();
         }
     } finally {
         lock.unlock();
     }
 }
}

 
@FunctionalInterface // 拒绝策略
interface RejectPolicy<T> {
 void reject(BlockingQueue<T> queue, T task);
}

  1. 任务生产者:用于生产任务,供线程池消费

main方法
  1. 测试代码

public static void main(String[] args) {
     ThreadPool threadPool = new ThreadPool(1,
         1000, TimeUnit.MILLISECONDS, 1, (queue, task)->{
         // 1. 死等
        // queue.put(task);
         // 2) 带超时等待
        // queue.offer(task, 1500, TimeUnit.MILLISECONDS);
         // 3) 让调用者放弃任务执行
        // log.debug("放弃{}", task);
         // 4) 让调用者抛出异常
        // throw new RuntimeException("任务执行失败 " + task);
         // 5) 让调用者自己执行任务
         task.run();
     });

     for (int i = 0; i < 4; i++) {
         int j = i;
         threadPool.execute(() -> {
         try {
             Thread.sleep(1000L);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
             log.debug("{}", j);
         });
     }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奇了个丑八怪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值