JUC并发编程-02:线程池相关

线程池

线程池就是一个可以复用线程的技术

  public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler){
        return null;
        }

*[ ] 各个参数的含义

  • corePoolSize:线程池的核心线程数(正式员工)
  • maximumPoolSize:指定的最大线程数量(核心线程数和临时线程数之和)
    最大员工总数:正式员工+外包员工
  • keepAliveTime:临时线程存活时间(外包合同期限)
  • unit:临时线程存活时间单位
  • workQueue:任务队列(项目)
  • threadFactory:线程工厂(招人的hr)
  • handler:线程池拒绝策略

内置线程池的使用

内置线程池使用Executors工具类去创建线程池
在这里插入图片描述

public class ThreadPool {
    public static void main(String[] args) {
        //创建固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //创建单线程线程池
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
        //创建动态线程线程池
        ExecutorService service = Executors.newCachedThreadPool();

    }
}

线程池的关闭

使用shutdown()或者shutdownNow()

  • shutdown():线程执行完后关闭;
  • shutdownNow():立即关闭,不管线程是否执行完毕;
    关闭线程池,如果不关闭,线程池中的线程会一直占用系统资源,会导致内存泄漏,主线程一直不会退出

excute方法和submit方法的区别

excute方法用来执行runable任务对象。而submit方法用来执行未来任务对象

  • 以计算1-100的任务为例
  • excuter方法
public class RunableExcuteTask implements Runnable{
    int goal;

    public RunableExcuteTask(int goal) {
        this.goal = goal;
    }

    @Override
    public void run() {
        int sum=0;
        for (int i = 1; i <=goal ; i++) {
            sum=sum+i;
        }
        System.out.println("1-"+goal+"的和是:"+sum);
    }
}

测试

public class ThreadPool {
    public static void main(String[] args) {
        Runnable task=new RunableExcuteTask(100);
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        threadPool.execute(task);
        threadPool.shutdown();
    }
}
  • submit方法
public class CallableExcuteTask implements Callable<Integer> {
    
    int goal;

    public CallableExcuteTask(int goal) {
        this.goal = goal;
    }

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 1; i <= goal; i++) {
            sum=sum+i;
        }
        return sum;
    }
}

测试

public class ThreadPool {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        CallableExcuteTask excuteTask = new CallableExcuteTask(100);
        Future<Integer> future = threadPool.submit(excuteTask);
        Integer integer = future.get();
        System.out.println(integer);
    }
}
  • 在处理异常方面

excute会在子线程中抛出异常,在主线程中捕捉不到;
submit不会立马抛出异常,而是会将异常暂时储存起来,等我们调用future.get()方法的时候才会抛出,并且可以在主线程中抛出。处理异常更方便

源码相关

tomcat线程池和jdk线程池的区别

tomcat线程池在创建的时候会提前准备好线程,并启动核心线程
在这里插入图片描述

线程池如何创建线程

     ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 8, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()
        );

如果有10个任务,在刚开始的时候,先创建10个核心线程,在第11个任务的时候放到任务队列中。当任务队列满了,核心线程还都在工作的时候,开始创建临时线程

  • 线程池中线程如何保活,而不是线程执行完毕就被销毁?

在线程池中通过阻塞队列的poll方法进行保活

线程池拒绝策略

  • AbortPolicy:直接拒绝
  • CallerRunsPolicy:线程池拒绝,调用主线程去执行任务
  • DiscardOldestPolicy:将最先的任务,丢出去,执行新任务
  • DiscardPolicy:什么都不做

线程池淘汰策略-正常执行完毕

需要明白的一点,如果10个核心线程,2个临时线程。如果任务执行完毕需要销毁线程,并不是说一定销毁的两个临时线程,而是12线程同时进入销毁方法(任务执行完毕会等待阻塞一段时间,如果有任务就去执行任务,没有任务12个线程才进入销毁处理方法进行CAS销毁,直到有任务或者线程数=核心线程数),根据CAS调度出两个线程进行销毁,剩余10个线程就是核心线程。任务执行完毕后
在这里插入图片描述
poll():等待阻塞;take():无限阻塞

线程池淘汰策略-线程异常

线程异常的时候,会将当前线程丢掉嘛?
线程池执行某个线程,不管是核心还是临时,一旦发生异常都会抛出异常,并且丢弃当前线程,并且新创建一个线程进行补充

线程池淘汰策略-线程关闭

线程关闭shutdown(),shutdownnow(),在实现的时候用了线程中断,而线程中断本质就是给线程调度器发了一个线程关闭的信号。具体的关闭操作还是看线程实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值