package com.zb.juc.test;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description:
* @Author:啵啵啵啵啵啵唧~~~
* @Date:2022/4/23
*/
@Slf4j(topic = "c.TestPool")
public class TestPool {
public static void main(String[] args) {
ThreadPool threadPool=new ThreadPool(2,1000,TimeUnit.MILLISECONDS,10);
for (int i = 0; i <5 ; i++) {
int j = i;
threadPool.execute(()->{
log.debug("{}",j);
});
}
}
}
@Slf4j(topic = "c.ThreadPool")
class ThreadPool{
/**
* 任务队列
*/
private BlockingQueue<Runnable> taskQueue;
/**
* 线程集合
*/
private HashSet<Worker> workers = new HashSet<>();
/**
* 核心线程数
*/
private int coreSize;
/**
* 获取任务的超时时间,过了超时间还没有任务可以让线程停止
*/
private long timeout;
/**
* 时间单位
*/
private TimeUnit timeUnit;
/**
* 初始化
* @param coreSize
* @param timeout
* @param timeUnit
* @param queueCapacity
*/
public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit,int queueCapacity) {
this.coreSize = coreSize;
this.timeout = timeout;
this.timeUnit = timeUnit;
this.taskQueue = new BlockingQueue<>(queueCapacity);
}
/**
* 用来执行任务
* @param task
*/
public void execute(Runnable task){
synchronized (workers){
//当任务数量没有超过核心线程数的时候,直接交给worker执行
if (workers.size()<coreSize){
Worker worker = new Worker(task);
log.debug("新增worker{},{}",worker,task);
workers.add(worker);
worker.start();
}else{
//如果任务数超过coreSize时,加入任务队列暂存
log.debug("加入任务队列{}",task);
taskQueue.put(task);
}
}
}
/**
* 封装线程对象
*/
class Worker extends Thread{
private Runnable task;
public Worker(Runnable task){
this.task=task;
}
@Override
public void run() {
//执行任务
//1、当task不为空,执行任务
//当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
task=null;
}
}
//一旦退出了循环因该
synchronized (workers){
log.debug("worker被移除{}",this);
workers.remove(this);
}
}
}
}
/**
* 定义一个阻塞队列
* @param
*/
class BlockingQueue<T>{
/**
* 1、任务队列
*/
private Deque<T> queue = new ArrayDeque<>();
/**
* 2、锁
*/
private ReentrantLock lock = new ReentrantLock();
/**
* 3、当任务队列当中没有任务的时候,消费者就进入等待状态,
* 这时候就需要一个消费者的条件变量
*/
private Condition emptyWaitSet = lock.newCondition();
/**
* 4、生产者也就需要一个条件变量
*/
private Condition fullWaitSet = lock.newCondition();
/**
* 5、阻塞队列的容量上限
*/
private int capcity;
/**
* 没有时间限制的阻塞获取
* @return
*/
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();
}
}
/**
* 阻塞添加
* @param element
*/
public void put(T element){
lock.lock();
try {
while(queue.size()==capcity){
//判断队列是否已满,满了的话生产者进入等待
try {
fullWaitSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//当有空位的时候,将新的任务放到队列的尾部
queue.addLast(element);
//添加完新的元素之后,需要唤醒等待当中的消费者队列,因为有新的任务进队列了
emptyWaitSet.signal();
}finally {
lock.unlock();
}
}
/**
* 有时间限制的阻塞获取
* @param timeout
* @param unit
* @return
*/
public T poll(long timeout , TimeUnit unit){
lock.lock();
try {
//将timeout时间转换成纳秒
long nanos = unit.toNanos(timeout);
while(queue.isEmpty()){
try {
//存在虚假唤醒的情况,所以可以拿到awaitNanos的返回值就是剩余的时间
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();
}
}
/**
* 获取阻塞队列的大小
* @return
*/
public int size(){
lock.lock();
try {
return queue.size();
}finally {
lock.unlock();
}
}
public BlockingQueue(int capacity) {
this.capcity = capacity;
}
}
@Override
public void run() {
//执行任务
//1、当task不为空,执行任务
//当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
task=null;
}
}
//一旦退出了循环因该
synchronized (workers){
log.debug("worker被移除{}",this);
workers.remove(this);
}
}
状态名 | 高三位 | 接受新任务吗? | 处理阻塞队列任务吗? | 说明 |
---|---|---|---|---|
RUNNING | 111 | Y | Y | |
SHUTDOWN | 000 | N | Y | 不会再接受新的任务,但是会将阻塞队列当中的剩余任务处理完毕 |
STOP | 001 | N | N | 会中断正在执行的任务,并抛弃阻塞队列任务 |
TIDYING | 010 | - | - | 任务全部执行完毕,活动线程为0即将进入终结 |
TERMINATED | 011 | - | - | 终结状态 |
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
public static ExecutorService newFixedThreadPool(int nThreads) {
//从这里我们可以看出核心线程数等于最大线程数,所以固定大小的这种创建线程池的方式没有核心线程
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
特点
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
@Slf4j(topic = "c.Test18")
public class Test18 {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2, new ThreadFactory() {
//创建一个原子类的整形用来设置线程名字的编号
private AtomicInteger t = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"myPool_t"+t.getAndIncrement());
}
});
pool.execute(()->{
log.debug("1");
});
pool.execute(()->{
log.debug("2");
});
pool.execute(()->{
log.debug("3");
});
}
}
public static ExecutorService newCachedThreadPool() {
//从这个构造方法可以看出,带缓冲的这个线程池它没有核心线程,全部都是紧急线程,只要在整数的最大范围内部创建的都是紧急线程
//通过他的这个时间上可以看出紧急线程的时间为60s
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
//他这个对列还是蛮特殊的
new SynchronousQueue<Runnable>());
}
评价
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
//核心线程和总线程数都是1
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
//给的是一个无界的阻塞对列
new LinkedBlockingQueue<Runnable>()));
}
区别:
void execute(Runnable command);
<T> Future<T> submit(Callable<T> task);
@Slf4j(topic = "c.Test19")
public class Test19 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<String> future = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
log.debug("running");
Thread.sleep(1000L);
return "ok";
}
});
log.debug("{}",future.get());
}
}
//-----------------------------------朗木达表达式版本-----------------------------------------
@Slf4j(topic = "c.Test19")
public class Test19 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<String> future = pool.submit(()-> {
log.debug("running");
Thread.sleep(1000L);
return "ok";
});
log.debug("{}",future.get());
}
}
//提交任务3 ->提交tasks中所有的任务
<T> List<Future<T>> involeAll(Colletion<? extends Callable<T>> task) throws InterrputedExeption;
ExecutorService pool = Executors.newFixedThreadPool(2);
List<Future<String>> futures = pool.invokeAll(Arrays.asList(
() -> {
log.debug("begin");
Thread.sleep(1000L);
return "1";
},
() -> {
log.debug("begin");
Thread.sleep(500L);
return "2";
},
() -> {
log.debug("begin");
Thread.sleep(2000L);
return "3";
}
));
futures.forEach(f->{
try {
log.debug("{}",f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
//提交tasks中所有的任务,那个任务先成功执行完毕,返回此任务结果,其他任务取消
<T> T involeAny(Colletion<? extends Callable<T>> task) throws InterrputedExeption,ExecutionException;
private static void method3(ExecutorService pool) throws InterruptedException, ExecutionException {
String s = pool.invokeAny(Arrays.asList(
() -> {
log.debug("begin");
Thread.sleep(1000L);
return "1";
},
() -> {
log.debug("begin");
Thread.sleep(500L);
return "2";
},
() -> {
log.debug("begin");
Thread.sleep(2000L);
return "3";
}
));
log.debug("{}",s);
}
/*
线程状态变为SHUTDOWN
- 不会再接收新的任务
- 但已经提交的任务会执行完
- 此方法不会阻塞线程的执行
*/
void shutdown();
public void shutdown(){
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try{
checkShutdownAccess();
//修改线程池状态 RUNNING->SHUTDOWN
advanceRunState(SHUTDOWN);
//仅仅会打断空闲线程
interrupIdleWorkers();
onShutdown();
}finally{
mainLock.unlock(;)
}
//尝试终结(没有运行的线程可以立刻终结,如果还有运行的线程也不会等待)
tryTerminate();
}
/*
线程状态变为STOP
- 不会再接收新的任务
- 会将队列当中的任务返回
- 并用interrupt的方式中断正在执行的任务
*/
List<Runnable> shutdownNow();;
public List<Runnable> shutdownNow(){
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try{
checkShutdownAcess();
//修改线程池的状态
advanceRunState(STOP);
//打断所有的线程
interruptWorkers();
//获取队列当中的剩余任务
tasks = drainQueue();
}finally{
mainLock.unlock();
}
//尝试终结
tryTerminate();
//返回我们获取到的任务
return t
}
让有限的工作线程轮流来异步处理无限多的任务。也可以将其归为分工模式,他的典型实现就是线程池,也体现了设计模式中的享元模式。
例如,海底捞的服务员(线程),轮流处理每位客人的点餐(任务),如果为每个客人都配备一名专属的服务员,那么成本就太高了
但是应该注意的是不同类型的任务应该选择不同的线程池,这样能够有效的避免饥饿,提高执行的效率,例如餐馆的工人既要招呼客人又要到后厨做菜,这样效率显然不咋样,如果分成服务员和厨师两种各干其事,各司其职,这样能大大提高效率。
/**
* @Description: 如何让每周四18:00:00定时执行任务
* @Author:啵啵啵啵啵啵唧~~~
* @Date:2022/4/26
*/
public class Test20 {
public static void main(String[] args) {
//获取当前时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
//获取当前之后的最近一个周四的时间
LocalDateTime time = now.withHour(18).withMinute(0).withSecond(0).with(DayOfWeek.THURSDAY);
//判断当前时间和是否大于本周周四 如果大于那么我们要找的周四就是下周的周四了
if (now.compareTo(time)>0){
time = time.plusWeeks(1);
}
System.out.println(time);
//使用这个带任务的调度的线程池
//initailDelay 代表当前时间和周四的差值
//period一周的间隔时间
long initailDelay = Duration.between(now,time).toMillis();
long period = 1000*60*60*24*7;
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
pool.scheduleAtFixedRate(()->{
System.out.println("running...");
},initailDelay,period, TimeUnit.MILLISECONDS);
}
}
LimitLatch 用来限流,可以控制最大的连接个数
Acceptor只负责写,接收新的socket连接
Poller只负责监听socket channel是否有可读i/o事件
一旦可读,封装一个任务对象socketProcessor,提交给Executor线程池处理
Executor线程池中间的工作线程最终负责处理请求