自定义线程池(详解)

自定义线程池(详解)

自定义任务队列

package com.hanxu.project42_multithreading.review.biji.ThreadPool;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

// 此处用T的目的,应为有Runnable,Callable两种可能
// 自定义任务队列
@Slf4j
public class BlockingQueue<T> {
    // 1.任务队列
    // 注意:ArrayDeque不是线程安全的
    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 Integer capcity;

    public BlockingQueue(Integer capcity) {
        this.capcity = capcity;
    }

    // 带超时的阻塞获取
    public T poll(long timeout, TimeUnit unit) {
        lock.lock();
        // 使用try语句,保证lock最后一定会被释放
        try {
            long nanos = unit.toNanos(timeout);
            while (queue.isEmpty()) {
                try {
                    if (nanos <= 0) {
                        return null;
                    }
                    // awaitNanos返回值为剩余时间,小于或等于零的值表示没有剩余时间
                    nanos = emptyWaitSet.awaitNanos(nanos);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = queue.removeFirst();
            // 用signal而不用signalAll的原因:因为一个工作线程只能随机唤醒一个fullWaitSet的线程(表达不太严谨)
            fullWaitSet.signal();
            return t;
        } 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.info("等待加入任务队列{}...", task);
                    nanos = fullWaitSet.awaitNanos(nanos);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info("加入任务队列{}", task);
            queue.addLast(task);
            // 用signal而不用signalAll的原因:因为一个emptyWaitSet的线程只能被一个工作线程来解决(表达不太严谨)
            emptyWaitSet.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }

    // 阻塞获取
    public T take() {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                try {
                    emptyWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = queue.removeFirst();
            // 用signal而不用signalAll的原因:因为一个工作线程只能随机唤醒一个fullWaitSet的线程(表达不太严谨)
            fullWaitSet.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }

    // 阻塞添加
    public void put(T task) {
        lock.lock();
        try {
            while (queue.size() == capcity) {
                try {
                    log.info("等待加入任务队列{}...", task);
                    fullWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info("加入任务队列{}", task);
            queue.addLast(task);
            // 用signal而不用signalAll的原因:因为一个emptyWaitSet的线程只能被一个工作线程来解决(表达不太严谨)
            emptyWaitSet.signal();
        } 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) {
                // 由用户决定是:
                // 1.死等
                // 2.带超时等待
                // 3.放弃任务执行
                // 4.抛出异常
                // 5.让用户自己执行任务
                rejectPolicy.reject(this, task);
            } else {
                log.info("加入任务队列{}", task);
                queue.addLast(task);
                emptyWaitSet.signal();
            }
        } finally {
            lock.unlock();
        }
    }
}

自定义拒绝策略接口

package com.hanxu.project42_multithreading.review.biji.ThreadPool;

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

自定义线程池

package com.hanxu.project42_multithreading.review.biji.ThreadPool;

import javafx.concurrent.Worker;
import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

@Slf4j
// 自定义线程池
// 用泛型T,因为有Runnable和Callable两种情况
public class ThreadPool {
    // 任务队列
    private BlockingQueue<Runnable> taskQueue;

    // 工作线程集合
    private HashSet<Worker> workers = new HashSet<>();

    // 核心线程数(决定创建几个工作线程)
    private Integer coreSize;

    // 获取任务的超时时间(工作线程队列没满时采用的)
    private Integer timeout;

    private TimeUnit timeUnit;

    private RejectPolicy<Runnable> rejectPolicy;

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

    //执行任务
    public void execute(Runnable task) {
        synchronized (workers) {
            // 当工作线程数没有超过coreSize时,新建worker对象并加入,worker对象开始处理任务队列中的任务
            if (workers.size() < coreSize) {
                Worker worker = new Worker(task);
                log.info("新增工作线程{}", worker);
                workers.add(worker);
                worker.start();
            } else {
                // 工作线程队列已经满了,并且任务还没处理完,没有空闲的worker对象来处理任务了,就把任务添加到任务队列中
                // 这里可以采用策略模式,由用户来进行选择
                // 1.死等
                // 2.带超时等待
                // 3.放弃任务执行
                // 4.抛出异常
                // 5.让用户自己执行任务
                taskQueue.tryPut(rejectPolicy, task);

            }
        }
    }

    class Worker extends Thread {
        private Runnable task;

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

        @Override
        public void run() {
            // 执行任务
            // ①:当task不为空,执行任务
            // ②:当task执行完毕,再接着从任务队列获取任务并执行
            while (task != null || (task = taskQueue.poll(timeout, timeUnit)) != null) {
                try {
                    log.info("正在执行{}....", task);
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    task = null;
                }
            }
            synchronized (workers) {
                log.info("工作线程{}被移除了", this);
                workers.remove(this);
            }
        }
    }
}

测试

package com.hanxu.project42_multithreading.review.biji.ThreadPool;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
public class Main {
    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,500,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) {
                    throw new RuntimeException(e);
                }
                log.info("{}", j);
            });
        }
    }
}

结果

①死等

20:51:44.411 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 新增工作线程Thread[Thread-0,5,main]
20:51:44.414 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14
20:51:44.414 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@3d0e272c....
20:51:44.414 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 等待加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf...
20:51:45.421 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 0
20:51:45.421 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14....
20:51:45.421 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf
20:51:45.421 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 等待加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030...
20:51:46.429 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 1
20:51:46.429 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf....
20:51:46.429 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030
20:51:47.432 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 2
20:51:47.432 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030....
20:51:48.440 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 3
20:51:49.447 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 工作线程Thread[Thread-0,5,main]被移除了

总计用时5秒

②带超时等待

20:59:27.818 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 新增工作线程Thread[Thread-0,5,main]
20:59:27.822 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14
20:59:27.822 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@60d58424....
20:59:27.822 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 等待加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf...
20:59:28.338 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 等待加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030...
20:59:28.832 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 0
20:59:28.832 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14....
20:59:28.832 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030
20:59:29.835 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 1
20:59:29.835 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@470e2030....
20:59:30.838 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 3
20:59:31.842 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 工作线程Thread[Thread-0,5,main]被移除了

总计用时4秒,并且第二个任务没有被执行

③放弃任务执行

21:01:31.604 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14
21:01:31.604 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@255cd55c....
21:01:31.605 [main] DEBUG com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 放弃com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf
21:01:31.605 [main] DEBUG com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 放弃com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@782830e
21:01:32.606 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 0
21:01:32.606 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14....
21:01:33.616 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 1
21:01:34.619 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 工作线程Thread[Thread-0,5,main]被移除了

可以看到第3和4个任务被放弃了

④抛出异常

21:02:45.871 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 新增工作线程Thread[Thread-0,5,main]
21:02:45.875 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14
21:02:45.875 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@255cd55c....
Exception in thread "main" java.lang.RuntimeException: 任务执行失败com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@606d8acf
	at com.hanxu.project42_multithreading.review.biji.ThreadPool.Main.lambda$main$0(Main.java:18)
	at com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue.tryPut(BlockingQueue.java:148)
	at com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool.execute(ThreadPool.java:54)
	at com.hanxu.project42_multithreading.review.biji.ThreadPool.Main.main(Main.java:24)
21:02:46.882 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 0
21:02:46.882 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14....
21:02:47.886 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 1
21:02:48.895 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 工作线程Thread[Thread-0,5,main]被移除了

⑤让用户自己执行任务

21:03:48.197 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 新增工作线程Thread[Thread-0,5,main]
21:03:48.200 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.BlockingQueue - 加入任务队列com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14
21:03:48.200 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@3548f505....
21:03:49.212 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 0
21:03:49.212 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 2
21:03:50.223 [main] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 3
21:03:50.223 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 正在执行com.hanxu.project42_multithreading.review.biji.ThreadPool.Main$$Lambda$2/212628335@69222c14....
21:03:51.234 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.Main - 1
21:03:52.238 [Thread-0] INFO com.hanxu.project42_multithreading.review.biji.ThreadPool.ThreadPool - 工作线程Thread[Thread-0,5,main]被移除了

可以看到任务3和4是由main线程执行的,1和2是由Thread-0线程执行的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值