线程池讲解

一:自定义线程池

(1)自定义一个拒绝策略接口

	public interface RejectPolicy<T> {
	   void reject(BlockingQueue<T> queue, T task);
	}

(2)定义队列

public 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 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();
    }
}

}

(3)线程池实现

                  public class ThreadPool {                                                                                                                              
// 任务队列
private BlockingQueue<Runnable> taskQueue;

// 构建线程池的时候,就应当确定拒绝策略
private RejectPolicy<Runnable> rejectPolicy;

// 线程集合,非线程安全
private HashSet<Worker> workers = new HashSet<>();

// 核心线程数
private int coreSize;

// 获取任务时的超时时间
private long timeout;

private TimeUnit timeUnit;

// 执行任务
public void execute(Runnable task) {
    // 当任务数没有超过 coreSize 时,直接交给 worker 对象执行
    // 如果任务数超过 coreSize 时,加入任务队列暂存,执行拒绝策略
    // 这段代码保护起来线程安全
    synchronized (workers) {
        if(workers.size() < coreSize) {
            Worker worker = new Worker(task);

            log.debug("新增 worker{}, {}", worker, task);
            workers.add(worker);
            worker.start();
        } else {
//                taskQueue.put(task);
                // 将拒绝策略全体下放,下放给调用者,也就是函数式接口,不写死,策略模式
                // 1) 死等
                // 2) 带超时等待
                // 3) 让调用者放弃任务执行
                // 4) 让调用者抛出异常
                // 5) 让调用者自己执行任务
                taskQueue.tryPut(rejectPolicy, task);
            }
        }
    }


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;
}

// 线程对象封装
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、当执行方式是execute时,可以看到堆栈异常的输出
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),即执行我们的方法,如果异常的话会throw x,所以可以看到异常。

2、当执行方式是submit时,堆栈异常没有输出,但是调用Future.get()方法时,可以捕获到异常
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),其实还会继续执FutureTask.run()方法,再在此方法中c.call()调用我们的方法,如果报错是setException(),并没有抛出异常。当我们去get()时,会将异常抛出。

參考链接:https://www.cnblogs.com/fanguangdexiaoyuer/p/12332082.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值