# threaddemo **Repository Path**: eason93/threaddemo ## Basic Information - **Project Name**: threaddemo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-05-29 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 多线程编程 ## Excutors Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可; 在面试过程中如果问到线程的三种模式,那么指的是fix,cached和single模式 创建线程的几种方法 * newFixedThreadPool * newSingleThreadExecutor * newCachedThreadPool * newScheduledThreadPool 为啥上面一共有四种方法,确是三种模式呢?很奇怪吧。 原因是因为定时执行的线程和其他的三种线程模式使用的原始方法不一样。 * newFixedThreadPool:实际执行ThreadPoolExecutor类(LinkedBlockingQueue) * newSingleThreadExecutor:实际执行ThreadPoolExecutor类(LinkedBlockingQueue) * newCachedThreadPool:实际执行ThreadPoolExecutor类,而这个调用的ThreadPoolExecutor的工作队列(SynchronousQueue) * newScheduledThreadPool:最大的不同是执行了ScheduledThreadPoolExecutor,而这个调用的ThreadPoolExecutor的工作队列**(DelayedWorkQueue)** Note:这里面指的fix,signle和cached都是指定的是corePoolSize(空闲的时候也不会收回)和maximumPoolSize(最大线程数);最大的问题是使用的工作队列是LinkedBlockingQueue,理论上是无限长的,在服务端运行的时候有可能出现(oom的故障);这个在后面会解决 | |newFixedThreadPool |newSingleThreadExecutor |newCachedThreadPool |newScheduledThreadPool | | --- | --- | --- | --- | --- | |线程长期维护数 |自定义大小 |1 |0 |自定义大小 | |最大的线程数 |自定义大小 |1 |Integer.MAX_VALUE |Integer.MAX_VALUE | |使用的链表 |LinkedBlockingQueue |LinkedBlockingQueue |SynchronousQueue |DelayedWorkQueue | ## 推荐的模式 Executors实际调用的也是ThreadPoolExecutor类,他会发生一些oom的问题是因为他用的工作队列是无限扩张的,在长期运行的服务器中可能会因此出现线程耗尽问题。 介绍一些ThreadPoolExecutor的构造方法 ``` ThreadPoolExecutor(int corePoolSize, 线程池,就算内容是空的也会一直占有资源,不会释放 int maximumPoolSize, 线程上限 long keepAliveTime, 系统回收线程的时间 TimeUnit unit, 时间的单位 BlockingQueue 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://mp.weixin.qq.com/s/hrPUZQEm6zp76Euj5ScaZw)