线程池(思想、创建及流程)

目录

线程池

Java中创建线程的方式有哪些?

实现 Runnable 接口和 Callable 接口的区别

追问1:线程池的好处?说几个Java中常见的线程池?说一下其中的参数和运行流程?

追问2:拒绝策略有哪些?

追问3:线程池的参数如何确定呢?

追问4:Java中常见的阻塞队列有哪些?

线程池中submit() 和 execute()方法有什么区别?


线程池

Java中创建线程的方式有哪些?

回答:Java中创建线程的方式有4种,分别是

(1)写一个类继承子Thread类,重写run方法

(2)写一个类重写Runable接口,重写run方法

(3)写一个类重写Callable接口,重写call方法

(4)使用线程池

实现 Runnable 接口和 Callable 接口的区别

区别:Runnable 接口不会返回结果或抛出检查异常,但是**Callable 接口**可以。所以,如果任务不需要返回结果或抛出异常推荐使用 Runnable 接口,这样代码看起来会更加简洁。工具类 Executors 可以实现 Runnable 对象和 Callable 对象之间的相互转换。

追问1:线程池的好处?说几个Java中常见的线程池?说一下其中的参数和运行流程?

池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。

线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。

使用线程池的好处

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

Executors 实现了以下四种类型的 ThreadPoolExecutor:

线程池有7大核心参数,分别是

corePoolSize:核心线程数

maximumPoolSize:线程池中最大线程数

keepAliveTime:多余空闲线程数的存活时间,当前线程数大于corePoolSize,并且等待时间大于keepAliveTime,多于线程或被销毁直到剩下corePoolSize为止。

TimeUnit unit: keepAliveTime的单位。

workQueue:阻塞队列,被提交但未必执行的任务。

threadFactory:用于创建线程池中工作线程的线程工厂,一般用默认的。

handler:拒绝策略,当堵塞队列满了并且工作线程大于线程池的最大线程数(maximumPoolSize)。

线程池中的执行流程:

(1)当线程数小于核心线程数的时候,使用核心线程数。

(2)如果核心线程数小于线程数,就将多余的线程放入任务队列(阻塞队列)中

(3)当任务队列(阻塞队列)满的时候,就启动最大线程数.

(4)当最大线程数也达到后,就将启动拒绝策略。

追问2:拒绝策略有哪些?

回答:有四种拒绝策略

1.ThreadPoolExecutor.AbortPolicy

线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常(即后面提交的请求不会放入队列也不会直接消费并抛出异常);

2.ThreadPoolExecutor.DiscardPolicy

丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃(也不会抛出任何异常,任务直接就丢弃了)。

3.ThreadPoolExecutor.DiscardOldestPolicy

丢弃队列最前面的任务,然后重新提交被拒绝的任务(丢弃掉了队列最前的任务,并不抛出异常,直接丢弃了)。

4.ThreadPoolExecutor.CallerRunsPolicy

由调用线程处理该任务(不会丢弃任务,最后所有的任务都执行了,并不会抛出异常)

追问3:线程池的参数如何确定呢?

回答:

一般需要确定核心线程数、最大线程数、任务队列和拒绝策略,这些需要根据实际的业务场景去设置,可以大致分为CPU密集型和IO密集型。

CPU密集型时,任务可以少配置线程数,大概和机器的cpu核数相当,这样可以使得每个线程都在执行任务。

IO密集型时,大部分线程都阻塞,故需要多配置线程数,2*cpu核数。

详细可以看一下《阿里调优手册》,需要的请私信我回复:阿里调优手册

追问4:Java中常见的阻塞队列有哪些?

ArrayBlockingQueue:是一个我们常用的典型的有界队列,其内部的实现是基于数组来实现的。

LinkedBlockingQueue 从它的名字我们可以知道,它是一个由链表实现的队列,这个队列的长度Integer.MAX_VALUE ,这个值是非常大的,几乎无法达到,对此我们可以认为这个队列基本属于一个无界队列(也又认为是有界队列)。此队列按照先进先出的顺序进行排序

SynchronousQueue 是一个不存储任何元素的阻塞队列,每一个put操作必须等待take操作,否则不能添加元素。同时它也支持公平锁和非公平锁。

PriorityBlockingQueue是一个支持优先级排序的无界阻塞队列,可以通过自定义实现 compareTo() 方法来指定元素的排序规则,或者通过构造器参数 Comparator 来指定排序规则。但是需要注意插入队列的对象必须是可比较大小的,也就是 Comparable 的,否则会抛出 ClassCastException 异常。

DelayQueue 是一个实现PriorityBlockingQueue的延迟获取的无界队列。具有“延迟”的功能。

线程池中submit() 和 execute()方法有什么区别?

        两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值