1.简单线程池的实现(含有简单的拒绝策略)
1.1 堵塞队列
package com.xjq.ThreadPool;
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;
/*
任务堵塞队列
*/
public class BlockingQueue<T> {
private int capecity; //堵塞队列容量
private Deque<T> queue; //双向链表
private ReentrantLock lock = new ReentrantLock(); //lock 锁
private Condition fullWaitSet = lock.newCondition(); //队列满时的条件变量
private Condition emptyWaitSet = lock.newCondition(); //队列空时的条件变量
public BlockingQueue(int capecity){
this.capecity = capecity;
this.queue = new ArrayDeque<>(capecity);
}
//堵塞队列获取元素
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 T poll(long times,TimeUnit timeUnit){
lock.lock();
long timeNs = timeUnit.toNanos(times); //时间统一转换为ns
try{
while(queue.isEmpty()){
try {
if (timeNs <= 0){
return null;
}
timeNs = emptyWaitSet.awaitNanos(timeNs); //返回剩余的等待时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T t = queue.removeFirst();
fullWaitSet.signal();
return t;
}finally {
lock.unlock();
}
}
/**
* 堵塞队列添加元素
*/
public void put(T t){
lock.lock();
try{
while(queue.size() == capecity){
try {
fullWaitSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.addLast(t);
emptyWaitSet.signalAll();
System.out.println(Thread.currentThread().getName()+"进入堵塞队列");
}finally {
lock.unlock();
}
}
/**
* 具有超时时间的插入堵塞队列
* @param task 任务
* @param time 时间
* @param timeUnit 时间单位
*/
public void offer(T task,long time,TimeUnit timeUnit){
lock.lock();
try {
long nanos = timeUnit.toNanos(time);
while(queue.size() == capecity){
try {
if (nanos <= 0){
System.out.println("超时,加入堵塞队列失败。。");
return;
}
nanos = fullWaitSet.awaitNanos(nanos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.addLast(task);
emptyWaitSet.signalAll();
}finally {
lock.unlock();
}
}
/**
* 实现拒绝策略
*/
public void tryPut(RejectPoliy rejectPoliy,T task){
lock.lock();
try {
if(queue.size() == capecity){
rejectPoliy.reject(this,task);
}else {
System.out.println("加入到堵塞队列。。。");
queue.addLast(task);
emptyWaitSet.signalAll();
}
}finally {
lock.unlock();
}
}
}
1.2 线程池
package com.xjq.ThreadPool;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
private BlockingQueue<Runnable> tasks; //堵塞队列
private HashSet<worker> workers = new HashSet<>(); //线程集合
private int capecity; //堵塞队列的容量
private int coreSize; //线程核心数
private long time; //设置超时时间
private TimeUnit timeUnit; //时间单位
private RejectPoliy<Runnable> rejectPoliy;
public ThreadPool(int coreSize, int capecity, long time, TimeUnit timeUnit,RejectPoliy<Runnable> rejectPoliy){
this.coreSize = coreSize;
this.capecity = capecity;
this.tasks = new BlockingQueue<>(capecity);
this.time = time;
this.timeUnit = timeUnit;
this.rejectPoliy = rejectPoliy;
}
/**
* 当线程数小于coreSize时,创建新的worker线程,加入到线程集合中。
* 否则,吧task任务加入到堵塞队列。
* @param task
*/
public void execute(Runnable task){
synchronized (workers){
if(workers.size() < coreSize){
worker w = new worker(task);
System.out.println("创建一个works");
workers.add(w);
w.start();
}else {
tasks.tryPut(rejectPoliy,task);
}
}
}
/**
* 执行的任务抽象类
*/
class worker extends Thread{
private Runnable task;
public worker(Runnable task){
this.task = task;
}
/**
* 1.当task不为空时,执行task,执行完task的run方法后,task置为空
* 2.当task执行完后继续去堵塞队列获取任务继续执行。
*/
@Override
public void run() {
while(task != null || (task = tasks.poll(time,timeUnit)) != null){
try{
task.run();
System.out.println("开始执行"+Thread.currentThread().getName());
}catch (Exception e) {
}finally {
task = null;
}
}
//work 线程结束后,从workers集合中移除
synchronized (workers){
workers.remove(this);
System.out.println("work线程结束。。。");
}
}
}
}
1.3 拒绝策略接口
package com.xjq.ThreadPool;
@FunctionalInterface //可以使用lamb表达式
public interface RejectPoliy<T> {
/**
* 用户自定义拒绝策略
* @param queue 任务堵塞队列
* @param task 待执行的任务
*/
void reject(BlockingQueue<T> queue,T task);
}
1.4 测试类
package com.xjq.ThreadPool;
import java.util.concurrent.TimeUnit;
public class TestPool {
public static void main(String[] args) {
ThreadPool pool = new ThreadPool(2,2,
1, TimeUnit.SECONDS,
(queue,task)->{
//四种自定义拒绝策略
//1.死等
//queue.put(task);
//2.超时放弃等待
// queue.offer(task,2,TimeUnit.SECONDS);
//3.调用者放弃执行任务
//
//4.调用者执行这个任务
task.run();
});
for (int i = 0; i < 5; i++) {
int num = i;
pool.execute(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num);
});
}
}
}
2. JDK中的线程池
2.1线程池类
2.2 线程池类构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:指定了线程池中的核心线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;
maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
其中含有救急线程,救急线程数=最大线程数 - 核心线程数。当新来一个任务,核心线程数和堵塞队列都满时,就会创建救急线程。
keepAliveTime:当救急线程没有任务执行时,存活时间。;
unit:keepAliveTime的单位
workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种;
threadFactory:线程工厂,用于创建线程,一般用默认即可;
handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务;
2.3 线程池状态
3.线程池实例
3.1 NewFixedThreadPool
3.2 newCachedThreadPool
3.3 newSingleThreadPool
3.4 总结
4.线程池应用-----设置定时任务
public class TimeWork {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now(); //获取当前时间 2020-10-16T17:28:14.413
//LocalDateTime 可以设置时间
LocalDateTime time = now.withHour(9).withMinute(52).withSecond(0).with(DayOfWeek.SATURDAY); //设置时间为本周六的9:52:0
if(time.compareTo(now) < 0){ //比较当前时间和设置的时间的天数差值
time = time.plusWeeks(1); //时间往后推一周
}
Duration duration = Duration.between(now,time); //设置两个时间的间隔
long initDely = duration.toMillis(); //把时间间隔转换为毫秒
System.out.println(initDely);
ScheduledThreadPoolExecutor deleyRun = new ScheduledThreadPoolExecutor(2); //带有定时任务的线程池对象
deleyRun.scheduleWithFixedDelay(
()->{
System.out.println("1");
}, //Runable 接口对象
initDely, //延迟多久开始执行程序
1000, //任务间隔多久重复执行
TimeUnit.MILLISECONDS); //时间单位
System.out.println(time);
}
}