Java线程(六):线程池

        自JDK5之后,Java推出了一个并发包,java.util.concurrent,在Java开发中,我们接触到了好多池的技术,String类的对象池、Integer的共享池、连接数据库的连接池、Struts1.3的对象池等等,池的最终目的都是节约资源,以更小的开销做更多的事情,从而提高性能。

        我们的web项目都是部署在服务器上,浏览器端的每一个request就是一个线程,那么服务器需要并发的处理多个请求,就需要线程池技术,下面来看一下Java并发包下如何创建线程池。

        1.  创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。

[java] view plaincopyprint?

ExecutorService threadPool = Executors.newFixedThreadPool(3);// 创建可以容纳3个线程的线程池

        2. 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。

[java] view plaincopyprint?

ExecutorService threadPool = Executors.newCachedThreadPool();// 线程池的大小会根据执行的任务数动态分配

        3. 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。

[java] view plaincopyprint?

ExecutorService threadPool = Executors.newSingleThreadExecutor();// 创建单个线程的线程池,如果当前线程在执行任务时突然中断,则会创建一个新的线程替代它继续执行任务

        4. 创建一个可安排在给定延迟后运行命令或者定期地执行的线程池。

[java] view plaincopyprint? ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果类似于Timer定时器

        每种线程池都有不同的使用场景,下面看一下这四种线程池使用起来有什么不同。

        1. FixedThreadPool

[java] view plaincopyprint?

  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. public class ThreadPoolTest {  
  4. public static void main(String[] args) {  
  5.         ExecutorService threadPool = Executors.newFixedThreadPool(3);  
  6. for(int i = 1; i < 5; i++) {  
  7. final int taskID = i;  
  8.             threadPool.execute(new Runnable() {  
  9. public void run() {  
  10. for(int i = 1; i < 5; i++) {  
  11. try {  
  12.                             Thread.sleep(20);// 为了测试出效果,让每次任务执行都需要一定时间
  13.                         } catch (InterruptedException e) {  
  14.                             e.printStackTrace();  
  15.                         }  
  16.                         System.out.println("第" + taskID + "次任务的第" + i + "次执行");  
  17.                     }  
  18.                 }  
  19.             });  
  20.         }  
  21.         threadPool.shutdown();// 任务执行完毕,关闭线程池
  22.     }  
  23. }  

        输出结果:

[java] view plaincopyprint?

  1. 第1次任务的第1次执行  
  2. 第2次任务的第1次执行  
  3. 第3次任务的第1次执行  
  4. 第2次任务的第2次执行  
  5. 第3次任务的第2次执行  
  6. 第1次任务的第2次执行  
  7. 第3次任务的第3次执行  
  8. 第1次任务的第3次执行  
  9. 第2次任务的第3次执行  
  10. 第3次任务的第4次执行  
  11. 第2次任务的第4次执行  
  12. 第1次任务的第4次执行  
  13. 第4次任务的第1次执行  
  14. 第4次任务的第2次执行  
  15. 第4次任务的第3次执行  
  16. 第4次任务的第4次执行  

        上段代码中,创建了一个固定大小的线程池,容量为3,然后循环执行了4个任务,由输出结果可以看到,前3个任务首先执行完,然后空闲下来的线程去执行第4个任务,在FixedThreadPool中,有一个固定大小的池,如果当前需要执行的任务超过了池大小,那么多于的任务等待状态,直到有空闲下来的线程执行任务,而当执行的任务小于池大小,空闲的线程也不会去销毁。

        2. CachedThreadPool

        上段代码其它地方不变,将newFixedThreadPool方法换成newCachedThreadPool方法。

        输出结果:

[java] view plaincopyprint?

  1. 第3次任务的第1次执行  
  2. 第4次任务的第1次执行  
  3. 第1次任务的第1次执行  
  4. 第2次任务的第1次执行  
  5. 第4次任务的第2次执行  
  6. 第3次任务的第2次执行  
  7. 第2次任务的第2次执行  
  8. 第1次任务的第2次执行  
  9. 第2次任务的第3次执行  
  10. 第3次任务的第3次执行  
  11. 第1次任务的第3次执行  
  12. 第4次任务的第3次执行  
  13. 第2次任务的第4次执行  
  14. 第4次任务的第4次执行  
  15. 第3次任务的第4次执行  
  16. 第1次任务的第4次执行  

        可见,4个任务是交替执行的,CachedThreadPool会创建一个缓存区,将初始化的线程缓存起来,如果线程有可用的,就使用之前创建好的线程,如果没有可用的,就新创建线程,终止并且从缓存中移除已有60秒未被使用的线程。

        3. SingleThreadExecutor        

       上段代码其它地方不变,将newFixedThreadPool方法换成newSingleThreadExecutor方法。       

输出结果:

[java] view plaincopyprint?

  1. 第1次任务的第1次执行  
  2. 第1次任务的第2次执行  
  3. 第1次任务的第3次执行  
  4. 第1次任务的第4次执行  
  5. 第2次任务的第1次执行  
  6. 第2次任务的第2次执行  
  7. 第2次任务的第3次执行  
  8. 第2次任务的第4次执行  
  9. 第3次任务的第1次执行  
  10. 第3次任务的第2次执行  
  11. 第3次任务的第3次执行  
  12. 第3次任务的第4次执行  
  13. 第4次任务的第1次执行  
  14. 第4次任务的第2次执行  
  15. 第4次任务的第3次执行  
  16. 第4次任务的第4次执行  

        4个任务是顺序执行的,SingleThreadExecutor得到的是一个单个的线程,这个线程会保证你的任务执行完成,如果当前线程意外终止,会创建一个新线程继续执行任务,这和我们直接创建线程不同,也和newFixedThreadPool(1)不同。

    4.ScheduledThreadPool

[java] view plaincopyprint?

  1. import java.util.concurrent.ScheduledExecutorService;  
  2. import java.util.concurrent.TimeUnit;  
  3. public class ThreadPoolTest {  
  4. public static void main(String[] args) {  
  5.         ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(1);  
  6. // 5秒后执行任务
  7.         schedulePool.schedule(new Runnable() {  
  8. public void run() {  
  9.                 System.out.println("爆炸");  
  10.             }  
  11.         }, 5, TimeUnit.SECONDS);  
  12. // 5秒后执行任务,以后每2秒执行一次
  13.         schedulePool.scheduleAtFixedRate(new Runnable() {  
  14. @Override
  15. public void run() {  
  16.                 System.out.println("爆炸");  
  17.             }  
  18.         }, 5, 2, TimeUnit.SECONDS);  
  19.     }  
  20. }  

ScheduledThreadPool可以定时的或延时的执行任务。

Java的并发包很强大,上面所说只是入门,随着学习深入,会有更多记录在博客里。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏源码之家

一键安装桌面及VNC

5686
来自专栏北京马哥教育

你所不知道的linux匿名管道知识

豌豆贴心提醒,本文阅读时间5分钟 相信很多在linux平台工作的童鞋, 都很熟悉管道符 '|', 通过它, 我们能够很灵活的将几种不同的命令协同起来完成一件任...

3135
来自专栏Hadoop实操

2.如何在RedHat7中实现OpenLDAP集成SSH登录并使用sssd同步用户

温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看。 Fayson的github:https://github.com/fayson/cdhproje...

3.2K9
来自专栏Java编程技术

Druid连接池原理学习

(1)、 如果设置了maxWait或者构造函数参数传入的为true,则创建的ReentrantLock为公平锁,否者为非公平锁 (2)、 如果设置了initi...

1.8K1
来自专栏腾讯Bugly的专栏

H5 缓存机制浅析 移动端 Web 加载性能优化

1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性。离线存储(也可称为缓存机制)是其中一个非常重要的特性。H5 引入的离...

3892
来自专栏pythonlove

Linux防火墙iptables(二)

上一篇文章我们说了一些iptables/netfilter的基础知识,本文我们来介绍一下iptables的规则编写。Iptables的规则可以概括的分为两个方面...

3842
来自专栏Android干货

打包错误--Error:A problem was found with the configuration of task ':app:packageRelease'.

3957
来自专栏battcn

利用 Nginx 实现限流

Nginx为我们提供了请求限制模块( ngx_http_limit_req_module)、基于令牌桶算法的流量限制模块( ngx_stream_limit_c...

1702
来自专栏Java架构沉思录

Linux常用Shell脚本知多少

在运维中,尤其是linux运维,都知道脚本的重要性,脚本会让我们的 运维事半功倍,所以学会写脚本是我们每个linux运维必须学会的一门功课,这里收藏linux运...

1391
来自专栏JavaEdge

Shiro实战(五) - 会话管理

Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器Tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理、会话事件...

4023

扫码关注云+社区

领取腾讯云代金券