多线程编程详解

多线程编程

Excutors

Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可;
创建线程的几种方法

  • newFixedThreadPool:实际执行ThreadPoolExecutor类(LinkedBlockingQueue)
  • newSingleThreadExecutor:实际执行ThreadPoolExecutor类(LinkedBlockingQueue)
  • newCachedThreadPool:实际执行ThreadPoolExecutor类,而这个调用的ThreadPoolExecutor的工作队列(SynchronousQueue)
  • newScheduledThreadPool:最大的不同是执行了ScheduledThreadPoolExecutor,而这个调用的ThreadPoolExecutor的工作队列**(DelayedWorkQueue)**

Note:这里面指的fix,signle和cached都是指定的是corePoolSize(空闲的时候也不会收回)和maximumPoolSize(最大线程数);最大的问题是使用的工作队列是LinkedBlockingQueue,理论上是无限长的,在服务端运行的时候有可能出现(oom的故障);这个在后面会解决

newFixedThreadPoolnewSingleThreadExecutornewCachedThreadPoolnewScheduledThreadPool
线程长期维护数自定义大小10自定义大小
最大的线程数自定义大小1Integer.MAX_VALUEInteger.MAX_VALUE
使用的链表LinkedBlockingQueueLinkedBlockingQueueSynchronousQueueDelayedWorkQueue

推荐的模式

Executors实际调用的也是ThreadPoolExecutor类,他会发生一些oom的问题是因为他用的工作队列是无限扩张的,在长期运行的服务器中可能会因此出现线程耗尽问题。
介绍一些ThreadPoolExecutor的构造方法

ThreadPoolExecutor(int corePoolSize,     线程池,就算内容是空的也会一直占有资源,不会释放
                   int maximumPoolSize,     线程上限
                   long keepAliveTime,       系统回收线程的时间
                   TimeUnit unit,               时间的单位
                   BlockingQueue<Runnable> workQueue,     工作队列(最主要的问题所在)
                   ThreadFactory threadFactory,                   线程工厂,默认会赋值DefaultThreadFactory
                   RejectedExecutionHandler handler)            拒绝策略

线程池工作策略

If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.

翻译:

  1. 小于核心线程,新线程增加
  2. 核心线程和更多线程再跑,会排队
  3. 如果一个请求不能排队了,一个新线程会创建。如果草果了最大的线程数,那么任务就会被拒绝。
    工作流程:corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略

推荐的创建模式:

ExecutorService executorService = new ThreadPoolExecutor(2, 2,
                0, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(512), // 使用有界队列,避免OOM
                new ThreadPoolExecutor.DiscardPolicy());  //拒绝模式

运行

ExecutorService一共有三种运行方法,具体区别如下

方法是否关心返回结果
Future submit(Runnable task, T result)否,虽然返回Future对象,但是总是null
Future submit(Callable task)是,通过get方法去获取
void execute(Runnable command)

拒绝模式

Executors默认创建的拒绝模式是一个DiscardPolicy
一共有4种拒绝的方式:

方式详细的解释
AbortPolicy抛出一个RejectedExecutionException的错误,然后不做任何处理
DiscardPolicy啥也不做,不抛错,也不做啥
DiscardOldestPolicy线程如果没有关系,那么会把这个错误的Queue移除
CallerRunsPolicy会判断多线程有没有关闭,没有的话继续执行一遍

工作队列

工作队列有很多种:
这个取决的就是排列的方式,和执行顺序;主要调用的是它的offer()方法

  • ArrayBlockingQueue:顺序执行
  • BlockingDeque:
  • DelayQueue:
  • LinkedBlockingDeque:
  • LinkedTransferQueue:
  • PriorityBlockingQueue:
  • DelayedWorkQueue:延时队列(newScheduledThreadPool的队列)
  • SynchronusQueue:同步队列
  • TransferQueue:
    这个有点多,暂时先这样,具体队列使用的环境也有点嗯。。。不了解

使用的场景

暂时问了一些阿里的童鞋:他们说一些异步场景的时候很有用,就丢给队列然后慢慢处理。
具体的场景由于我的工作经验也比较有限,所以暂时不能列举出一些很好的例子。

使用过程中问题

  • executors不使用shutdown不会退出程序:这个是在等待新的任务进来。
  • executors使用的过程中测试抛错,发现任务执行不下去:这是由于错误抛错到了main程序了,所以导致任务进行不下去。
  • Note:newScheduledThreadPool的执行方法,如果是submit的话也是直接运行的;有几个定时的方法schedule(),scheduleAtFixedRate(),scheduleWithFixedDelay();这个名字已经很明显了,就不解释了。’

参考

  1. Java 线程池详解

测试代码:https://gitee.com/eason93/threaddemo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值