线程与线程池(面试自用)

谈谈你对线程、线程池以及使用多线程的经验?

我们知道线程是CPU调度和分配的最小单位,线程的创建的方式有继承Thread类、实现Runnable接口或者实现Callable接口。他们之前的区别是 Java是单继承多实现的,一旦我们创建的线程类集成了Thread类之后就不能继承其他父类了,所以不推荐使用继承的方式,Runnable类是所有多线程类的父接口,通过实现该接口的run()方法;第三种是实现Callable接口,通过实现该接口的call()方法,调用call方法或配合FutureTask调用FutureTask的run方法或者配合Future 通过调用get方法创建线程并可以获取call方法的返回值。Runnable接口和Callable接口的区别是Runnable的run方法是无返回值的,而Callable的call方法是有返回值的,Callable通过配合ExecuterService 、Future使用可以获取call方法的返回值。

至于线程池,线程池是把创建好的线程放入池中,等到需要的时候从池中拿出来使用,不会频繁的去创建和销毁线程,因为创建和销毁线程的花销是比较大的。这样做能提高效率以及方便对线程进行管理,常见的线程池有newFixedThreadPool()、newWorkStealingPool()、newSingleThreadExecutor()、newCacheThreadPool()、newScheduledThreadPool()。

newSingleThreadExecutor()创建的是一个单线程的线程池,适用于需要保证顺序执行的各个任务,并且在任意时间点都不会有多个线程活动的场景。

newFixedThreadPool()创建的是一个固定大小的线程池,采用的是无界阻塞队列,所以线程数量是不会变化的,适用于可以预测线程数量的业务中,

newCacheThreadPool()创建的是一个可以无限扩大的线程池,适用服务器负载比较轻但短期异步任务比较多的场景,默认空闲线程回收时间是60s。

newScheduledThreadPool()创建的是一个定时的的可周期执行的线程池,适用于需要多个后台任务定时执行的场景。

newWorkStealingPool()创建的是一个当前CPU可用数量的线程的线程池,能够合理利用CPU对任务进行并行操作,适用于很耗时的任务。

但是阿里开发手册给出最好不要使用Executors中的创建线程池的方法创建线程,而是采用ThreadPoolExecutor类来创建线程,ThreadPoolExecutor类的构造方法中的参数包含corePoolSize 核心线程数,maximumPoolSize 最大线程数;keepAliveTime 非核心线程存活时间;unit keepAliveTime的时间单位;workQueue 用来存储等待执行任务的阻塞队列;threadFactory 创建线程的工厂类 handler 拒绝策略;   

关于核心线程数,最大线程数和空闲线程存活时间之间的关系:

1、当有任务进来时,如果当前线程数小于核心线程数,不管是否有空闲线程,都会创建线程去处理任务

2、当线程数目大于核心线程数目时,有任务进来,则把任务存放到阻塞队列中,等待核心线程空闲时去处理

3、当阻塞队列满了之后,如果当前线程数小于最大线程数,则创建新的线程去处理任务

4、当线程数等于最大线程数并且阻塞队列已经满了,这时会采用拒绝策略。

5、当线程数大于核心线程数,并且线程空闲时间大于keepAliveTime时,会对空闲线程进行回收。

6、如果线程池设置了allowCoreThreadTimeOut(true),核心线程达到空闲时间阈值之后也会被回收。

 

关于阻塞队列,常见的阻塞队列有:LinkedBlockingQueue、ArrayBlockingQueue、priorityBlockingQueue、DelayQueue、SychonousQueue、LinkedTransfQueue、LinkedBlockingDeque

简单介绍下就是:

LinkedBlockingQueue 是一个链表结构组成的可选边界的阻塞队列

ArrayBlockingQueue  是一个数组结构组成的有界阻塞队列

PriorityBlockingQueue 是一个支持优先级的无界阻塞队列

DelayQueue 是一个使用优先级队列实现的无界阻塞队列

SynchronousQueue 是一个没有缓冲或者说不存储元素的阻塞队列

LinkedTransfQueue 是一个链表结构的无界阻塞队列

LinkedBlockingDeque 是一个双向链表的可选边界的阻塞队列

至于线程工厂,我们可以实现ThreadFactory线程工厂接口的newThread方法,自定义自己的创建线程的方法或使用默认线程工厂类DefaultThreadFactory。

当线程数量等于最大线程数并且阻塞队列已经满了时,线程池会采用拒绝策略阻止任务入队,常见的拒绝策略有:

ThreadPoolExecutor.AbortPolicy 拒绝并抛弃,但是会抛出RejectedExecutionException

ThreadPoolExecutor.DiscardPolicy 拒绝并抛弃任务,不会抛出异常

ThreadPoolExecutor.DiscardOldestPolicy  当新任务到来时,会把阻塞队列头部的任务抛弃,然后执行改任务

ThreadPoolExecutor.CallerRunsPolicy 当任务到来时,会让当前的Executor来执行该任务,但是可能会阻塞当前Executor线程,导致线程池无法进行任务调度。

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值