- 浏览: 39099 次
- 性别:
- 来自: 北京
最新评论
1. 线程池是啥子
一说到池子,大家都会想到数据库连接池那种对象池。本来嘛,现在倡导废物回收利用的节能环保绿色新社会嘛。其实线程池的初衷就是能将已经创建好了的线程对象重复利用。之前咱们说过对于一个分布式系统,离不开高并发、多线程的支持。那么无论是HTTP方式的,还是文件方式的,面对海量的客户端请求,作为服务端如果对于请求使用单线程阻塞方式显然是不可能的。JDK5之后为咱们提供了现成的线程池对象。我们用几个现成的JDK辅助类就能将线程对象池化。线程池实际上也是对象池的一种特例,对象池主要是池化那些创建比较费劲、耗费资源比较大的大对象,比如你的重量级UI组件,比如你的IO文件对象。当然了,如果您的企业不差钱,买得起优越的服务器,仅仅针对一个不到100并发场景的小场景,每个数据服务终端都是当时很顶级的服务器,50w的IBM服务器,那另当别论,您愿意怎么折腾就怎么折腾!别以为笔者在这里开玩笑,确实有这样的现象。某政府的电子政务系统,花的纳税人的钱,买的都是高档服务器,配置的集群环境。最后的使用量,并发量……唉,花纳税人的钱就是不痛不痒啊,不提了,那个面子工程……
2. 为什么用这玩意
言归正传,我们来看为什么要用线程池这个东西。上面我们提到了对象池,对象池的目的就是为了重复利用创建起来比较复杂的大对象的。那么线程呢?线程对象不大的话也要用池子管理它吗?实际上线程池适合于短时间运行的、并发量比较大的线程对象场景。就好比说你去快餐店吃东西,快餐店不可能为每一个顾客都布置一个桌子,一把椅子,固定就那么10几个座位。您买完了一个汉堡,一杯可乐,在座位上吧唧吧唧2口,喝口水,ok,擦擦嘴,抬屁股走人即可。从买餐到坐下吃饭,不到5分钟。因为这家快餐店是知名品牌,有很高的客户群体。没办法,对于每个客户而言就那么珍贵的5分钟啊。轻轻的您走了,正如您轻轻地来。线程池就是适用于以上这种场景,并发量非常巨大,但是每个访问的时间又是极短的。如果是每次访问需要的时间比较多的情况下就不适合这种场景,就适合建立新线程对象的场景。就好比说您现在关心吃饭的质量,吃饭喜欢细嚼慢咽,带着老婆,唱着歌,吃着火锅然后服务员突然跟您说:“对不起,先生,您time out了。”您怎么想。这种场景就适合大排档,所有客户都是露天桌椅,如果来了新客户就应该在外面搭个桌子(new一个新线程),招呼客户去外面吃大排档了。
如果线程对象请求的时间过长,那么很多新线程对象都在线程等待队列中等着。等待的队伍越来越长不说,客户端也一直处于等待状态,总有一个时间,客户端会没有耐心的。那么我们在开发中,大概在什么情况下使用线程池来维护线程对象呢。
3. 怎么用这玩意
讲了线程池是什么,又描述了线程池的使用场景,那么如何使用线程池呢。咱们先来看一个实例
Java代码 收藏代码
1. package threadPool;
2.
3. import java.util.concurrent.ExecutorService;
4. import java.util.concurrent.Executors;
5.
6. public class TestThreadPool {
7.
8. /**
9. * @param args
10. */
11. public static void main(String[] args) {
12.
13. // 创建线程池
14. ExecutorService exec = Executors.newFixedThreadPool(3);
15.
16. // 建立100个线程
17. for (int index = 0; index < 100; index++) {
18. Runnable run = new Runnable() {
19. public void run() {
20.
21. // 随机毫秒
22. long time = (long) (Math.random() * 500);
23. System.out.println("Sleeping "
24. + Thread.currentThread().getName() + ":" + time
25. + "ms");
26. try {
27. Thread.sleep(time);
28.
29. } catch (InterruptedException e) {
30. e.printStackTrace();
31. }
32.
33. }
34.
35. };
36.
37. //执行
38. exec.execute(run);
39. }
40.
41. //关闭
42. exec.shutdown();
43.
44. }
45. }
package threadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThreadPool {
/**
* @param args
*/
public static void main(String[] args) {
// 创建线程池
ExecutorService exec = Executors.newFixedThreadPool(3);
// 建立100个线程
for (int index = 0; index < 100; index++) {
Runnable run = new Runnable() {
public void run() {
// 随机毫秒
long time = (long) (Math.random() * 500);
System.out.println("Sleeping "
+ Thread.currentThread().getName() + ":" + time
+ "ms");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//执行
exec.execute(run);
}
//关闭
exec.shutdown();
}
}
以上程序先创建了一个线程池,Executors可以创建各式各样的线程池,这个我们后面再说,先不去管它,就知道先创建了个线程池即可。在构造参数里限定线程池的容量是3个,也就是说线程池允许的活动状态线程个数是3个(这家快餐馆也太小了,就给开了3个座位,不够看美女的啊~),在同一时间内,3个线程任务争抢CPU资源执行任务。这里每一个Runnable对象相当于一个要吃饭的人,他们必须有桌子才能吃饭,而线程池为他们提供了桌子、椅子,Runnable们有了桌子、椅子才能吃东西。其他为活动的线程都在线程队列中等待着。最后调用关闭线程池的方法shutdown();,如果不调用该方法那么线程池还可以继续运行线程对象的任务,如果调用了再执行线程对象会抛出java.util.concurrent.RejectedExecutionException。拒绝执行线程任务。
4. 几个扩展线程池
从以上程序执行情况来看实际上是ThreadPoolExecutor对象负责执行,代码段Executors.newFixedThreadPool(3)是创建ThreadPoolExecutor对象的。只是ThreadPoolExecutor对象有很多有参的构造函数,合理的利用ThreadPoolExecutor的构造函数成为了使用线程池,创建线程池的关键点。Executors提供了很多的静态方法来创建ThreadPoolExecutor对象,其底层实质上就是调用ThreadPoolExecutor不同的构造函数,或者在相同构造函数上使用不同的实参来对外进行服务。这样对于客户端调用者来说不必记住那些复杂的参数含义,按需调用Executors静态方法就能获得自己想要的线程池执行对象,大大简化了创建线程池的难度。这也是装饰器模式的体现,把复杂的东西对客户端以一种简单的方式呈现出来。客户端不必被那些繁琐的参数、创建过程吓到。
1.首先咱们就上面那个程序的例子,上面那个程序创建线程池是如下语句
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newFixedThreadPool(3);
// 创建线程池
ExecutorService exec = Executors.newFixedThreadPool(3);
它实际上是调用了如下代码
Java代码 收藏代码
1. public static ExecutorService newFixedThreadPool(int nThreads) {
2. return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
3. }
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
大家看到了,客户端调用的时候仅仅传入了一个参数——活动线程的个数。
之前使用newFixedThreadPool的效果大家看到了,在一个时刻,一直是3个线程任务再争抢资源,如果这个时候来新的线程任务了,那么会将其放到LinkedBlockingQueue中放着。LinkedBlockingQueue的大小是整型的最大数——2147483647。这也是最普通的使用场景。限制线程的执行数量,也减少了高并发下多线程之间的资源切换争抢时间。
2.下面是一个仅单线程池的创建例子
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newSingleThreadExecutor();
// 创建线程池
ExecutorService exec = Executors.newSingleThreadExecutor();
底层为
Java代码 收藏代码
1. public static ExecutorService newSingleThreadExecutor() {
2. return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
3. }
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
细心地读者发现了,这个和调用
Java代码 收藏代码
1. ExecutorService exec = Executors.newFixedThreadPool(1)
ExecutorService exec = Executors.newFixedThreadPool(1)
没什么区别,这里需要说明的是它的使用场景,这个是单线程的线程池,在一个时刻只能一个线程任务去执行,这个具体的场景在哪里?其实根据实际情况来看,它更适合于做多任务的汇总,这个多任务之间没有任何层次关系,都是并列的。比如云计算节点单机A、节点B、节点C月底凌晨要做流量汇总,运维的时候是要按需收费的!这个时候就需要每个节点机器的用户appid、流量、吞吐汇报上来做报表汇总。此时数据上报是多线程任务的,从每个节点接收成功后启动计算功能的线程,之后将计算线程逐一放到这个单一的线程池进行计算、入本地库、记日志、单节点的成本BI计算等等操作完成后,下一个node的线程再进行汇总。使用单一线程考虑到2方面,第一每条数据都要严格的进行log记录,以便进行智能的统计BI分析,第二就是在统计的主线程中,需要用到种种局部临时变量,所以这种情况是最适合不过了。当然了,读者要是问我有其他方式解决吗?当然有其他方式。我们这里仅仅讨论newSingleThreadExecutor的适用场景,至少在此场景下newSingleThreadExecutor是解决方案之一。抱歉的是,因为一些特殊的原因,笔者不能将这部分实例代码分享出来,涉及到一些其他利益,大家懂得的,呵呵。
3.还有就是缓存线程池,创建方式如下
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newCachedThreadPool();
// 创建线程池
ExecutorService exec = Executors.newCachedThreadPool();
当放入池中的新线程发现没有可复用的池对象的时候,那么就创建一个新的线程对象放入池中。在一定的时间,默认是60秒后,线程池会自动将其赶出池子,也就是说之前露天的大排档吃完的地方在60s内还可以重复利用。服务员在60s后发现依然没人占用地方。ok,回收之。但是,如果此时线程池依然很忙碌,没有可复用的线程资源,那没办法,只能重新创建一个新线程并添加到池中。
相比较咱们之前的newFixedThreadPool方法,它最大的特点就是回收资源、清除超时(60s)、闲置的线程资源,因此它占用系统资源方面不是很大。而newFixedThreadPool方法,只要线程池不关闭,池子里面的资源不会回收。也就是,您哪怕是买一杯麦当劳的咖啡,也可以在里面占一个座位,喝上一整天,看一整天的书,没办法,谁让咱这个线程执行得慢呢。
4.最后一个要介绍的是类似于Timer类的ScheduledExecutorService,这个就是属于使用周期性任务的线程了,大家对Timer或者任务调度已经很明白了,不再赘述了,这里就将网友的一段代码示例给大家即可
Java代码 收藏代码
1. ScheduledExecutorService executor = Executors
2. .newScheduledThreadPool(10);
3.
4. Runnable task = new Runnable() {
5.
6. @Override
7. public void run() {
8.
9. System.out.println("task over");
10.
11. }
12.
13. };
14.
15. executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);
ScheduledExecutorService executor = Executors
.newScheduledThreadPool(10);
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("task over");
}
};
executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);的意思就是线程放到周期线程池中,第一次延迟10秒执行,每过2秒则执行一次任务。
5. 总结
线程池的使用其实还可以深入,如果自己感兴趣也可以造造这个轮子。笔者觉得比较难的是创建线程池的时候的创建参数,上面集中线程池是已有的,适合大多数线程池场景的创建方法,如果在特殊情况下需要自己手工new线程池,参数的选择,直接影响了线程池的效率以及功能。最后还是唠叨一下,线程池适合执行短时间连接请求的线程任务,并且访问量比较巨大的情况。对于消耗时间比较长的连接,您最好还是用别的办法。
PS:时间长短是相对来说的,一个笑话:“您觉得一分钟是长还是短?那得看您是在厕所外面排队还是在厕所里面方便……”
各位网友原谅我将其放到了“分布式”的大标题下面,笔者想将其弄成一个系列而已。
一说到池子,大家都会想到数据库连接池那种对象池。本来嘛,现在倡导废物回收利用的节能环保绿色新社会嘛。其实线程池的初衷就是能将已经创建好了的线程对象重复利用。之前咱们说过对于一个分布式系统,离不开高并发、多线程的支持。那么无论是HTTP方式的,还是文件方式的,面对海量的客户端请求,作为服务端如果对于请求使用单线程阻塞方式显然是不可能的。JDK5之后为咱们提供了现成的线程池对象。我们用几个现成的JDK辅助类就能将线程对象池化。线程池实际上也是对象池的一种特例,对象池主要是池化那些创建比较费劲、耗费资源比较大的大对象,比如你的重量级UI组件,比如你的IO文件对象。当然了,如果您的企业不差钱,买得起优越的服务器,仅仅针对一个不到100并发场景的小场景,每个数据服务终端都是当时很顶级的服务器,50w的IBM服务器,那另当别论,您愿意怎么折腾就怎么折腾!别以为笔者在这里开玩笑,确实有这样的现象。某政府的电子政务系统,花的纳税人的钱,买的都是高档服务器,配置的集群环境。最后的使用量,并发量……唉,花纳税人的钱就是不痛不痒啊,不提了,那个面子工程……
2. 为什么用这玩意
言归正传,我们来看为什么要用线程池这个东西。上面我们提到了对象池,对象池的目的就是为了重复利用创建起来比较复杂的大对象的。那么线程呢?线程对象不大的话也要用池子管理它吗?实际上线程池适合于短时间运行的、并发量比较大的线程对象场景。就好比说你去快餐店吃东西,快餐店不可能为每一个顾客都布置一个桌子,一把椅子,固定就那么10几个座位。您买完了一个汉堡,一杯可乐,在座位上吧唧吧唧2口,喝口水,ok,擦擦嘴,抬屁股走人即可。从买餐到坐下吃饭,不到5分钟。因为这家快餐店是知名品牌,有很高的客户群体。没办法,对于每个客户而言就那么珍贵的5分钟啊。轻轻的您走了,正如您轻轻地来。线程池就是适用于以上这种场景,并发量非常巨大,但是每个访问的时间又是极短的。如果是每次访问需要的时间比较多的情况下就不适合这种场景,就适合建立新线程对象的场景。就好比说您现在关心吃饭的质量,吃饭喜欢细嚼慢咽,带着老婆,唱着歌,吃着火锅然后服务员突然跟您说:“对不起,先生,您time out了。”您怎么想。这种场景就适合大排档,所有客户都是露天桌椅,如果来了新客户就应该在外面搭个桌子(new一个新线程),招呼客户去外面吃大排档了。
如果线程对象请求的时间过长,那么很多新线程对象都在线程等待队列中等着。等待的队伍越来越长不说,客户端也一直处于等待状态,总有一个时间,客户端会没有耐心的。那么我们在开发中,大概在什么情况下使用线程池来维护线程对象呢。
3. 怎么用这玩意
讲了线程池是什么,又描述了线程池的使用场景,那么如何使用线程池呢。咱们先来看一个实例
Java代码 收藏代码
1. package threadPool;
2.
3. import java.util.concurrent.ExecutorService;
4. import java.util.concurrent.Executors;
5.
6. public class TestThreadPool {
7.
8. /**
9. * @param args
10. */
11. public static void main(String[] args) {
12.
13. // 创建线程池
14. ExecutorService exec = Executors.newFixedThreadPool(3);
15.
16. // 建立100个线程
17. for (int index = 0; index < 100; index++) {
18. Runnable run = new Runnable() {
19. public void run() {
20.
21. // 随机毫秒
22. long time = (long) (Math.random() * 500);
23. System.out.println("Sleeping "
24. + Thread.currentThread().getName() + ":" + time
25. + "ms");
26. try {
27. Thread.sleep(time);
28.
29. } catch (InterruptedException e) {
30. e.printStackTrace();
31. }
32.
33. }
34.
35. };
36.
37. //执行
38. exec.execute(run);
39. }
40.
41. //关闭
42. exec.shutdown();
43.
44. }
45. }
package threadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThreadPool {
/**
* @param args
*/
public static void main(String[] args) {
// 创建线程池
ExecutorService exec = Executors.newFixedThreadPool(3);
// 建立100个线程
for (int index = 0; index < 100; index++) {
Runnable run = new Runnable() {
public void run() {
// 随机毫秒
long time = (long) (Math.random() * 500);
System.out.println("Sleeping "
+ Thread.currentThread().getName() + ":" + time
+ "ms");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//执行
exec.execute(run);
}
//关闭
exec.shutdown();
}
}
以上程序先创建了一个线程池,Executors可以创建各式各样的线程池,这个我们后面再说,先不去管它,就知道先创建了个线程池即可。在构造参数里限定线程池的容量是3个,也就是说线程池允许的活动状态线程个数是3个(这家快餐馆也太小了,就给开了3个座位,不够看美女的啊~),在同一时间内,3个线程任务争抢CPU资源执行任务。这里每一个Runnable对象相当于一个要吃饭的人,他们必须有桌子才能吃饭,而线程池为他们提供了桌子、椅子,Runnable们有了桌子、椅子才能吃东西。其他为活动的线程都在线程队列中等待着。最后调用关闭线程池的方法shutdown();,如果不调用该方法那么线程池还可以继续运行线程对象的任务,如果调用了再执行线程对象会抛出java.util.concurrent.RejectedExecutionException。拒绝执行线程任务。
4. 几个扩展线程池
从以上程序执行情况来看实际上是ThreadPoolExecutor对象负责执行,代码段Executors.newFixedThreadPool(3)是创建ThreadPoolExecutor对象的。只是ThreadPoolExecutor对象有很多有参的构造函数,合理的利用ThreadPoolExecutor的构造函数成为了使用线程池,创建线程池的关键点。Executors提供了很多的静态方法来创建ThreadPoolExecutor对象,其底层实质上就是调用ThreadPoolExecutor不同的构造函数,或者在相同构造函数上使用不同的实参来对外进行服务。这样对于客户端调用者来说不必记住那些复杂的参数含义,按需调用Executors静态方法就能获得自己想要的线程池执行对象,大大简化了创建线程池的难度。这也是装饰器模式的体现,把复杂的东西对客户端以一种简单的方式呈现出来。客户端不必被那些繁琐的参数、创建过程吓到。
1.首先咱们就上面那个程序的例子,上面那个程序创建线程池是如下语句
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newFixedThreadPool(3);
// 创建线程池
ExecutorService exec = Executors.newFixedThreadPool(3);
它实际上是调用了如下代码
Java代码 收藏代码
1. public static ExecutorService newFixedThreadPool(int nThreads) {
2. return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
3. }
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
大家看到了,客户端调用的时候仅仅传入了一个参数——活动线程的个数。
之前使用newFixedThreadPool的效果大家看到了,在一个时刻,一直是3个线程任务再争抢资源,如果这个时候来新的线程任务了,那么会将其放到LinkedBlockingQueue中放着。LinkedBlockingQueue的大小是整型的最大数——2147483647。这也是最普通的使用场景。限制线程的执行数量,也减少了高并发下多线程之间的资源切换争抢时间。
2.下面是一个仅单线程池的创建例子
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newSingleThreadExecutor();
// 创建线程池
ExecutorService exec = Executors.newSingleThreadExecutor();
底层为
Java代码 收藏代码
1. public static ExecutorService newSingleThreadExecutor() {
2. return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
3. }
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
细心地读者发现了,这个和调用
Java代码 收藏代码
1. ExecutorService exec = Executors.newFixedThreadPool(1)
ExecutorService exec = Executors.newFixedThreadPool(1)
没什么区别,这里需要说明的是它的使用场景,这个是单线程的线程池,在一个时刻只能一个线程任务去执行,这个具体的场景在哪里?其实根据实际情况来看,它更适合于做多任务的汇总,这个多任务之间没有任何层次关系,都是并列的。比如云计算节点单机A、节点B、节点C月底凌晨要做流量汇总,运维的时候是要按需收费的!这个时候就需要每个节点机器的用户appid、流量、吞吐汇报上来做报表汇总。此时数据上报是多线程任务的,从每个节点接收成功后启动计算功能的线程,之后将计算线程逐一放到这个单一的线程池进行计算、入本地库、记日志、单节点的成本BI计算等等操作完成后,下一个node的线程再进行汇总。使用单一线程考虑到2方面,第一每条数据都要严格的进行log记录,以便进行智能的统计BI分析,第二就是在统计的主线程中,需要用到种种局部临时变量,所以这种情况是最适合不过了。当然了,读者要是问我有其他方式解决吗?当然有其他方式。我们这里仅仅讨论newSingleThreadExecutor的适用场景,至少在此场景下newSingleThreadExecutor是解决方案之一。抱歉的是,因为一些特殊的原因,笔者不能将这部分实例代码分享出来,涉及到一些其他利益,大家懂得的,呵呵。
3.还有就是缓存线程池,创建方式如下
Java代码 收藏代码
1. // 创建线程池
2. ExecutorService exec = Executors.newCachedThreadPool();
// 创建线程池
ExecutorService exec = Executors.newCachedThreadPool();
当放入池中的新线程发现没有可复用的池对象的时候,那么就创建一个新的线程对象放入池中。在一定的时间,默认是60秒后,线程池会自动将其赶出池子,也就是说之前露天的大排档吃完的地方在60s内还可以重复利用。服务员在60s后发现依然没人占用地方。ok,回收之。但是,如果此时线程池依然很忙碌,没有可复用的线程资源,那没办法,只能重新创建一个新线程并添加到池中。
相比较咱们之前的newFixedThreadPool方法,它最大的特点就是回收资源、清除超时(60s)、闲置的线程资源,因此它占用系统资源方面不是很大。而newFixedThreadPool方法,只要线程池不关闭,池子里面的资源不会回收。也就是,您哪怕是买一杯麦当劳的咖啡,也可以在里面占一个座位,喝上一整天,看一整天的书,没办法,谁让咱这个线程执行得慢呢。
4.最后一个要介绍的是类似于Timer类的ScheduledExecutorService,这个就是属于使用周期性任务的线程了,大家对Timer或者任务调度已经很明白了,不再赘述了,这里就将网友的一段代码示例给大家即可
Java代码 收藏代码
1. ScheduledExecutorService executor = Executors
2. .newScheduledThreadPool(10);
3.
4. Runnable task = new Runnable() {
5.
6. @Override
7. public void run() {
8.
9. System.out.println("task over");
10.
11. }
12.
13. };
14.
15. executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);
ScheduledExecutorService executor = Executors
.newScheduledThreadPool(10);
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("task over");
}
};
executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(task, 10, 2, TimeUnit.SECONDS);的意思就是线程放到周期线程池中,第一次延迟10秒执行,每过2秒则执行一次任务。
5. 总结
线程池的使用其实还可以深入,如果自己感兴趣也可以造造这个轮子。笔者觉得比较难的是创建线程池的时候的创建参数,上面集中线程池是已有的,适合大多数线程池场景的创建方法,如果在特殊情况下需要自己手工new线程池,参数的选择,直接影响了线程池的效率以及功能。最后还是唠叨一下,线程池适合执行短时间连接请求的线程任务,并且访问量比较巨大的情况。对于消耗时间比较长的连接,您最好还是用别的办法。
PS:时间长短是相对来说的,一个笑话:“您觉得一分钟是长还是短?那得看您是在厕所外面排队还是在厕所里面方便……”
各位网友原谅我将其放到了“分布式”的大标题下面,笔者想将其弄成一个系列而已。
发表评论
-
linux 下载并安装Memcache服务器端
2015-07-25 15:50 684下载并安装Memcache服务器端 服务器端主要是安装memc ... -
spring的jar功能说明及个jar包之间的依赖关系
2015-07-24 14:39 350spring.jar是包含有完整发布的单个jar包,sprin ... -
sping
2015-07-07 09:45 539一、简单的用ApplicationContext做测试的话,获 ... -
大型互联网站解决高并发的常见策略
2015-04-10 14:13 654一个运营的系统在正式 ... -
excel
2014-08-22 10:24 558HSSFSheet sheet = workbook. ... -
调用存储过程
2012-08-23 09:36 843public void queryProce( final i ... -
在线打开word
2012-06-11 12:59 1309在线打开word . 2010-05-10 17:16 184 ... -
Lucene_3.0_原理与代码分析.
2011-12-09 17:54 677Lucene_3.0_原理与代码分析 -
JAVA中的IO流.txt
2011-11-03 17:32 932JAVA中的IO流是非常重要的知识点,用于文件内容的写入、读取 ... -
quanxian
2011-05-20 16:18 532quanxian -
Restrictions
2011-05-20 11:23 786Restrictions dev.firnow.com ... -
权限设计
2011-05-20 11:21 658权限设计权限设计 -
struts 跳转 action
2011-05-20 11:20 711<result name="showList& ... -
java
2011-05-11 23:04 530大点javaeye -
md5 加密
2011-05-06 15:56 647md5 加密 -
java 导出 excel
2011-05-04 21:49 998java导出Excel例举方式 方法一:导出Excel数据 ... -
java 读取 Excel
2011-05-02 15:44 645private void initMachine() thro ...
相关推荐
使用阿里巴巴的德鲁伊连接池链接数据库,可以连接主流数据库
Delphi XE2 DataSnap 链接池 数据集池 池例子
基本实现java代码关于适用jdbc动态连接池链接数据库代码。
Delphi Xe2 Datasnap 链接池数据集池
JNDI数据链接池经典
poolman数据库链接池所有源文件
jdbc链接池大全
delphi数据连接池设置出数据并发产生数据连接中断,提高上数据查询速度
使用反射实现jdbc数据库连接,并且支持oracle,mysql,sqlsever三种数据,另外做了简单的jndi连接次操作
jdbc的几种用法,以及数据库连接池的用法和性能比较
JavaJNDI 数据链接池及 属性文件读取数据链接信息
数据库连接池~~~数据库连接池~~~数据库连接池~~~数据库连接池
tomcat配置链接池代码终极版
ADO.NET链接对象(SqlConnection或者OracleConnection)默认情况都开启连接池(平时编程时可能会忽略)。当我们调用Close或者Dispose方法时,实际并不断开连接,而是把连接放回连接池,再次使用时候重连接池中取得...
一个链接池的小项目,比较简单,当时非常清楚
JDBC链接池
使用apache的commons-pool2 构建 FTPClient连接池 有FtpClientFactory、FtpClientPool、FtpConfig、FtpOperate 四个类组成 还有ftp连接池的一些配置参数信息在ftp.properties文件中 注释完整欢迎大家下载使用
提供一个最基本的java 连接池,通过配置文件的配置 就可以实现的对数据库的管理
RabbitMQ连接池+SpringBoot实现。通过连接池实现将高效的管理RabbitMQ的Connection,并与springboot进行整合,实现消息发送,获取队列列表等功能。基于此可以进行更多功能的扩充。