- 浏览: 1148345 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (138)
- JAVA基础 (22)
- Spring (6)
- 设计模式 (2)
- JDK源码 (3)
- java-功能组件 (4)
- 游戏项目 (2)
- linux (13)
- Oracle (2)
- struts (1)
- 字符集 (8)
- HTTP协议 (2)
- java-网络通信 (1)
- 工具软件推荐 (2)
- tomcat (1)
- java-容器框架 (2)
- java-IO框架 (2)
- java-多线程框架 (4)
- java-NIO框架 (0)
- jquery (2)
- 工具使用 (12)
- 加密解密 (1)
- redis (2)
- maven (2)
- svn (1)
- eclipse (1)
- mysql (11)
- 我的收藏 (1)
- JAVA进阶 (26)
- 运维 (3)
- protocol buffer (1)
- 优秀博主 (1)
- nginx (1)
- 算法 (2)
- 故障排查 (4)
- 粤语歌曲 (6)
- 生活总结 (6)
- 高并发 (4)
- 语言训练 (1)
- 读书笔记 (5)
- 诗歌 (1)
- tomcat源码学习 (1)
- 软件词汇 (1)
- git (1)
最新评论
-
ryuhi:
一个是来源source,一个是来源方序列号seq这两个数据要怎 ...
高并发的核心技术-幂等的实现方案 -
xuezhongyu01:
无量 写道Master-Gao 写道理论感觉还行,可以代码我还 ...
高并发的核心技术-幂等的实现方案 -
无量:
Master-Gao 写道理论感觉还行,可以代码我还是不会写。 ...
高并发的核心技术-幂等的实现方案 -
phil_jing:
@RequestParam 默认 true
SpringMVC注解@RequestParam全面解析 -
aguai0:
aguai0 写道第五条里的如果要获取任务执行结果,用Comp ...
JAVA进阶----ThreadPoolExecutor机制
ThreadPoolExecutor机制
一、概述
1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务;
2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。
3、先来了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池
二、核心构造方法讲解
下面是ThreadPoolExecutor最核心的构造方法
构造方法参数讲解
重点讲解:
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。
1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
线程管理机制图示:
三、Executors提供的线程池配置方案
1、构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理
2、构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁
3、构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行
4、构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的
四、定制属于自己的非阻塞线程池
方法中建立一个核心线程数为30个,缓冲队列有10个的线程池。每个线程任务,执行时会先睡眠3秒,保证提交10任务时,线程数目被占用完,再提交30任务时,阻塞队列被占用完,,这样提交第41个任务是,会交给CustomRejectedExecutionHandler 异常处理类来处理。
提交任务的代码如下:
注意:41以后提交的任务就不能正常处理了,因为,execute中提交到任务队列是用的offer方法,如上面代码,这个方法是非阻塞的,所以就会交给CustomRejectedExecutionHandler 来处理,所以对于大数据量的任务来说,这种线程池,如果不设置队列长度会OOM,设置队列长度,会有任务得不到处理,接下来我们构建一个阻塞的自定义线程池
五、定制属于自己的阻塞线程池
解释:当提交任务被拒绝时,进入拒绝机制,我们实现拒绝方法,把任务重新用阻塞提交方法put提交,实现阻塞提交任务功能,防止队列过大,OOM,提交被拒绝方法在下面
总结:
1、用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM
2、如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务
3、最大线程数一般设为2N+1最好,N是CPU核数
4、核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数
5、如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果
new Thread(new Runnable() {
@Override
public void run() {
pool.take().get();
}
}).start();
核心线程满了,接下来进队列,队列也满了,创建新线程,直到达到最大线程数,之后再超出,才会进入拒绝rejectedExecution里面,之后才可以改阻塞
put不进去,阻塞在这里
没有重写execute,只是把execute源码帖了上去,上大家看下,知道为什么阻塞的线程池要自己定制
汗, 忙中出错, 抱歉我看错了.
博主是阿里的吧, 楼主的好多文章我在去阿里面试的时候都遇到了.
面试的时候我这个问题就回答错了,赶紧回来补补课.
一、概述
1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务;
2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。
3、先来了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池
二、核心构造方法讲解
下面是ThreadPoolExecutor最核心的构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
构造方法参数讲解
参数名 | 作用 |
corePoolSize | 核心线程池大小 |
maximumPoolSize | 最大线程池大小 |
keepAliveTime | 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间 |
TimeUnit | keepAliveTime时间单位 |
workQueue | 阻塞任务队列 |
threadFactory | 新建线程工厂 |
RejectedExecutionHandler | 当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理 |
重点讲解:
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。
1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
线程管理机制图示:
三、Executors提供的线程池配置方案
1、构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
2、构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
3、构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
4、构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, new DelayedWorkQueue(), threadFactory); }
四、定制属于自己的非阻塞线程池
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class CustomThreadPoolExecutor { private ThreadPoolExecutor pool = null; /** * 线程池初始化方法 * * corePoolSize 核心线程池大小----10 * maximumPoolSize 最大线程池大小----30 * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列 * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂 * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时, * 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)), * 任务会交给RejectedExecutionHandler来处理 */ public void init() { pool = new ThreadPoolExecutor( 10, 30, 30, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(10), new CustomThreadFactory(), new CustomRejectedExecutionHandler()); } public void destory() { if(pool != null) { pool.shutdownNow(); } } public ExecutorService getCustomThreadPoolExecutor() { return this.pool; } private class CustomThreadFactory implements ThreadFactory { private AtomicInteger count = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1); System.out.println(threadName); t.setName(threadName); return t; } } private class CustomRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 记录异常 // 报警处理等 System.out.println("error............."); } } // 测试构造的线程池 public static void main(String[] args) { CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor(); // 1.初始化 exec.init(); ExecutorService pool = exec.getCustomThreadPoolExecutor(); for(int i=1; i<100; i++) { System.out.println("提交第" + i + "个任务!"); pool.execute(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("running====="); } }); } // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了 // exec.destory(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }
方法中建立一个核心线程数为30个,缓冲队列有10个的线程池。每个线程任务,执行时会先睡眠3秒,保证提交10任务时,线程数目被占用完,再提交30任务时,阻塞队列被占用完,,这样提交第41个任务是,会交给CustomRejectedExecutionHandler 异常处理类来处理。
提交任务的代码如下:
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
注意:41以后提交的任务就不能正常处理了,因为,execute中提交到任务队列是用的offer方法,如上面代码,这个方法是非阻塞的,所以就会交给CustomRejectedExecutionHandler 来处理,所以对于大数据量的任务来说,这种线程池,如果不设置队列长度会OOM,设置队列长度,会有任务得不到处理,接下来我们构建一个阻塞的自定义线程池
五、定制属于自己的阻塞线程池
package com.tongbanjie.trade.test.commons; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class CustomThreadPoolExecutor { private ThreadPoolExecutor pool = null; /** * 线程池初始化方法 * * corePoolSize 核心线程池大小----1 * maximumPoolSize 最大线程池大小----3 * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(5)====5容量的阻塞队列 * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂 * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时, * 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)), * 任务会交给RejectedExecutionHandler来处理 */ public void init() { pool = new ThreadPoolExecutor( 1, 3, 30, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(5), new CustomThreadFactory(), new CustomRejectedExecutionHandler()); } public void destory() { if(pool != null) { pool.shutdownNow(); } } public ExecutorService getCustomThreadPoolExecutor() { return this.pool; } private class CustomThreadFactory implements ThreadFactory { private AtomicInteger count = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1); System.out.println(threadName); t.setName(threadName); return t; } } private class CustomRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { // 核心改造点,由blockingqueue的offer改成put阻塞方法 executor.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } } } // 测试构造的线程池 public static void main(String[] args) { CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor(); // 1.初始化 exec.init(); ExecutorService pool = exec.getCustomThreadPoolExecutor(); for(int i=1; i<100; i++) { System.out.println("提交第" + i + "个任务!"); pool.execute(new Runnable() { @Override public void run() { try { System.out.println(">>>task is running====="); TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }); } // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了 // exec.destory(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }
解释:当提交任务被拒绝时,进入拒绝机制,我们实现拒绝方法,把任务重新用阻塞提交方法put提交,实现阻塞提交任务功能,防止队列过大,OOM,提交被拒绝方法在下面
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) // 进入拒绝机制, 我们把runnable任务拿出来,重新用阻塞操作put,来实现提交阻塞功能 reject(command); }
总结:
1、用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM
2、如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务
3、最大线程数一般设为2N+1最好,N是CPU核数
4、核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数
5、如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果
评论
13 楼
aguai0
2017-11-28
aguai0 写道
第五条里的
如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取
如何重新开一个线程获取结果?
如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取
如何重新开一个线程获取结果?
new Thread(new Runnable() {
@Override
public void run() {
pool.take().get();
}
}).start();
12 楼
aguai0
2017-11-28
第五条里的
如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取
如何重新开一个线程获取结果?
如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取
如何重新开一个线程获取结果?
11 楼
无量
2017-11-16
LLLLLLLLLLLLLLLLLLLLEE 写道
你好,模仿着也写了代码,发现当线程池满了之后,rejectedExecution()方法没被调用啊。是哪里出问题了吗?
一开始使用的是默认的handler,发现没抛出异常,然后就传了自己重写的handler对象,发现,也没有打印日志。
这样的话,阻塞线程池我也无法实现了。
一开始使用的是默认的handler,发现没抛出异常,然后就传了自己重写的handler对象,发现,也没有打印日志。
这样的话,阻塞线程池我也无法实现了。
核心线程满了,接下来进队列,队列也满了,创建新线程,直到达到最大线程数,之后再超出,才会进入拒绝rejectedExecution里面,之后才可以改阻塞
10 楼
LLLLLLLLLLLLLLLLLLLLEE
2017-11-04
你好,模仿着也写了代码,发现当线程池满了之后,rejectedExecution()方法没被调用啊。是哪里出问题了吗?
一开始使用的是默认的handler,发现没抛出异常,然后就传了自己重写的handler对象,发现,也没有打印日志。
这样的话,阻塞线程池我也无法实现了。
一开始使用的是默认的handler,发现没抛出异常,然后就传了自己重写的handler对象,发现,也没有打印日志。
这样的话,阻塞线程池我也无法实现了。
9 楼
无量
2017-10-23
lqi 写道
private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 核心改造点,由blockingqueue的offer改成put阻塞方法
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
楼主这儿有点没明白:当队列满了 走这个 这个时候队里已经满了 还能put进去吗?没明白这个位置的代码 望楼主赐教
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 核心改造点,由blockingqueue的offer改成put阻塞方法
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
楼主这儿有点没明白:当队列满了 走这个 这个时候队里已经满了 还能put进去吗?没明白这个位置的代码 望楼主赐教
put不进去,阻塞在这里
8 楼
lqi
2017-08-11
private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 核心改造点,由blockingqueue的offer改成put阻塞方法
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
楼主这儿有点没明白:当队列满了 走这个 这个时候队里已经满了 还能put进去吗?没明白这个位置的代码 望楼主赐教
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 核心改造点,由blockingqueue的offer改成put阻塞方法
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
楼主这儿有点没明白:当队列满了 走这个 这个时候队里已经满了 还能put进去吗?没明白这个位置的代码 望楼主赐教
7 楼
无量
2017-04-11
zhangfeiyu2005 写道
博主,有个地方我没看懂,想请教下,谢谢!
文中重写了execute方法,为何要这么做呢?重写的execute和自定义的CustomThreadPoolExecutor之间有何联系?
文中重写了execute方法,为何要这么做呢?重写的execute和自定义的CustomThreadPoolExecutor之间有何联系?
没有重写execute,只是把execute源码帖了上去,上大家看下,知道为什么阻塞的线程池要自己定制
6 楼
zhangfeiyu2005
2017-04-09
博主,有个地方我没看懂,想请教下,谢谢!
文中重写了execute方法,为何要这么做呢?重写的execute和自定义的CustomThreadPoolExecutor之间有何联系?
文中重写了execute方法,为何要这么做呢?重写的execute和自定义的CustomThreadPoolExecutor之间有何联系?
5 楼
bingyingao
2017-04-07
mark一下
4 楼
studysoft
2017-03-03
studysoft 写道
在JDK8中看到cachedThreadPool已经变了呢.maximumPoolSize就意义了吧.
//...
汗, 忙中出错, 抱歉我看错了.
博主是阿里的吧, 楼主的好多文章我在去阿里面试的时候都遇到了.
面试的时候我这个问题就回答错了,赶紧回来补补课.
3 楼
studysoft
2017-03-03
在JDK8中看到cachedThreadPool已经变了呢.maximumPoolSize就意义了吧.
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
2 楼
我才是此去经年
2016-09-05
1 楼
sjzcmlt
2016-01-26
好牛逼,谢谢
发表评论
-
区块链!每个人都要了解下--十分钟洞见区块链的前世今生
2018-04-27 12:32 804区块链!每个人都要了解下--十分钟洞见区块链的前世今生 ... -
区块链!每个人都要了解下--十分钟洞见区块链的前世今生
2018-04-27 12:09 0为啥要讲区块链呢,因为它太火了,火到什么程度呢 ... -
项目打包,报软件包、类不存在问题排查过程
2017-05-16 17:13 5989项目打包报,软件包、类不存在问题排查过程 一、背景 ... -
海量数据存储--分库分表策略详解
2017-04-12 19:59 7337海量数据存储--分库分表策略详解 一、背景: 系统刚 ... -
jstack详解
2017-02-17 11:15 1918jstack http://www.open-open.co ... -
jdk-源码中的一些坑
2017-02-13 15:17 1255jdk-源码中的一些坑 1. Runnable接口的命名简直 ... -
一次mysql死锁的排查过程
2016-11-21 10:04 11344一次mysql死锁的排查过程 一、背景 17号晚上要吃饭 ... -
JVM调优:选择合适的GC collector (三)
2016-11-15 20:51 1277CMS Collector 在很多地方,CMS Collec ... -
JVM调优:选择合适的GC collector (二)
2016-11-15 20:47 1001http://blog.csdn.net/historya ... -
JVM调优:选择合适的GC collector (一)
2016-11-15 20:45 1276http://blog.csdn.net/historyas ... -
jstat查看gc情况
2016-11-10 10:11 2498jps(Java Virtual Machine Proces ... -
tomcat源码学习(一) eclipse导入tomcat源码
2016-10-31 20:05 14191. 到官网下载Tomcat源代码,这里用到的是apache- ... -
深入分析ClassLoader
2016-10-27 23:27 786转(原文http://blog.csdn.net/xya ... -
业务架构模板
2016-10-20 19:56 1913业务架构模板 默认一个高大上的业务系统需要具备的技术点和对应 ... -
如何写一个强壮的JOB任务
2016-10-18 15:00 3020如何写一个强壮的JOB任务 1. JOB跑一半断电了,不能产 ... -
mybatis.xml中sql编写规范
2016-10-18 14:54 6263一、越少的代码,越强悍的功能,xml里面应该6个sql语句就够 ... -
数据库设计规范
2016-10-17 23:29 65871. 数据库设计基本规范 领域驱动表内容 ... -
全局主键生成器-支持单JVM1秒近1000万订单生成
2016-05-03 20:46 5683全局主键生成器 介绍: 相对于DB自增序列的全局主键生成器, ... -
解决并发下累计的问题
2016-04-25 11:58 2129package com.tongbanjie.trade.te ... -
系统开发中的坑
2016-03-15 15:39 2807系统开发中的坑 这个是在公司分享的一个ppt,整理下发到博客里 ...
相关推荐
在Java进阶学习中,你需要掌握以下几个关键的知识点: 1. 高级数据结构与算法:理解并能熟练运用ArrayList、LinkedList、HashMap等集合框架,深入研究Set、Queue、Stack等接口及其实现类。同时,学习并应用高级排序...
Java的锁机制包括内置锁(synchronized)、显式锁(Lock接口)、读写锁(ReadWriteLock)等,适用于不同的同步需求。同步处理线程间的共享数据,而异步则让任务并发执行,等待结果。 AOP(面向切面编程)用于分离...
《Java进阶实战教程》 Java,这门广泛使用的编程语言,因其强大的跨平台能力、丰富的类库和高效性能,一直以来都是开发者们的首选工具。在深入学习Java的过程中,掌握其高级特性和应用技巧是提升技能的关键。本资料...
Java进阶学习教程中的第13章主要涵盖了JVM(Java虚拟机)和多线程两个核心概念。JVM是Java程序运行的基础,它负责解释执行字节码文件,并提供了Java语言的跨平台特性。Java程序通过JVM与操作系统交互,使得程序可以...
### Java进阶知识点详解 #### 第一章:基本语法 ##### 关键字 - **static**:用于定义...以上是对Java进阶知识点的详细解析,覆盖了基本语法、JDK源码分析等多个方面,有助于深入理解Java语言的核心机制及高级特性。
以下将详细介绍第25章可能涉及的知识点,并根据通常的Java进阶内容进行扩展。 第25章可能涵盖的主题包括但不限于: 1. **多线程**:Java提供了强大的多线程支持,这可能是第25章的重点。学生可能需要理解和掌握`...
《Java语言程序设计-进阶篇》是Java编程学习的重要参考资料,尤其对于已经掌握Java基础知识的开发者来说,这本书是进一步提升技能的关键。该书的第八版涵盖了Java编程的诸多高级主题,旨在帮助读者深入理解Java的...
在Java编程中,多线程是实现并发执行任务的...总之,Java的多线程机制是其强大之处,通过合理利用线程和同步机制,可以编写出高效、稳定的并发程序。在实际开发中,了解并熟练掌握这些知识点对于提升软件性能至关重要。
"Java进阶高手课-并发编程透彻理解"这一课程旨在深入剖析Java并发编程的核心概念和技术,通过实际项目演练帮助学习者建立起扎实的并发编程基础。 课程首先会介绍并发编程的基础理论,包括线程的基本概念、创建与...
### Java开发进阶知识点概述 #### 一、多线程深入理解 在Java开发中,多线程技术是一项非常重要的技能。它可以帮助开发者构建出高效、响应迅速的应用程序。接下来,我们将详细介绍多线程的基本概念及其高级应用。 ...
作为一款软件/插件学习资料,这个PPT涵盖了Java语言的基础、进阶以及实战应用等多个层面,对于程序员尤其是初学者来说,是提升Java技能的宝贵工具。 1. **Java基础** - 类与对象:Java是一种面向对象的语言,PPT会...
在“疯狂Java语言编程 Java入门到进阶教程 16.多线程”这一部分,主要探讨了Java中的并发编程,这是多核处理器环境下提高程序性能的关键技术。首先,讲解了线程的基本概念,线程是进程内的执行单元,是操作系统分配...
### Java语言程序设计进阶知识点解析 #### 一、Java语言概述 - **定义与特点**:Java是一种广泛使用的高级编程语言,由Sun Microsystems在1995年首次发布。它具有面向对象、平台无关性、健壮性、安全性等特点。 - ...
本练习集专注于提升你在Java并发编程中的技巧,通过一系列逐步进阶的代码实例,帮助你掌握从基础到高级的并发概念。 首先,我们从“线程安全”开始。线程安全是指在多线程环境下,一个类或方法能够正确地处理并发...
这份笔记包含了从基础到高级的各类Java编程概念,是学习和进阶Java技术的宝贵资料。Markdown格式使得内容易于阅读和编辑,适合在各种Markdown查看器或文本编辑器中打开。 ### 一、Java基础 1. **语法基础**:了解...
本资源“java编程1-50例”显然是一份涵盖了基础到进阶的Java编程实例集,旨在帮助学习者通过实际操作来掌握Java语言的关键概念和技术。 1. **基础语法** - 变量声明:Java中的变量必须先声明后使用,包括数据类型...
"Java100例-学习Java必看资源"这个压缩包提供了一百个精心挑选的Java编程实例,旨在帮助初学者和进阶者巩固基础,理解并掌握Java的核心概念和技术。下面,我们将详细探讨这些实例所涵盖的知识点,并对每个实例进行...
2. **Java进阶** - 泛型:学习泛型的概念,理解其在代码复用和类型安全上的作用。 - 集合框架:深入研究ArrayList、LinkedList、HashSet、HashMap等集合类的实现原理及使用场景。 - 文件I/O:掌握File类,理解流...
Java SE(标准版)是Java开发平台的核心部分,主要...这个"java_se 学习总结项目"中的资料应该涵盖了以上所有知识点,对于初学者来说是一份宝贵的资源,通过实践和学习,可以全面系统地掌握Java SE的基础和进阶知识。