目录
实现 Runnable 接口和 Callable 接口的区别
追问1:线程池的好处?说几个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都有这些方法。