并发库应用之三 & 线程池与定时器应用
在TCP服务器编程模型的原理,每一个客户端连接用一个单独的线程为之服务,当与客户端的会话结束时,线程也就结束了,即每来一个客户端连接,服务器端就要创建一个新线程。如果访问服务器的客户端很多,那么服务器要不断地创建和销毁线程,这将严重影响服务器的性能。线程池的概念与此类似,首先创建一些线程,它们的集合称为线程池,当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。
假设如果没有线程池的话,那么就需要在run方法中不停判断,还有没有任务需要执行
线程池:先创建多个线程放在线程池中,当有任务需要执行时,从线程池中找一个空闲线程执行任务,任务完成后,并不销毁线程,而是返回线程池,等待新的任务安排。
线程池编程中,任务是提交给整个线程池的,并不是提交给某个具体的线程,而是由线程池从中挑选一个空闲线程来运行任务。一个线程同时只能执行一个任务,可以同时向一个线程池提交多个任务。
线程池创建方法
创建一个拥有固定线程数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);
2. 创建一个缓冲线程池,线程池中的线程数根据任务多少自动增删动态变化
ExecutorService threadPool = Executors.newCachedThreadPool();
3. 创建一个只有一个线程的线程池,与单线程一样,但它的好处是保证池子里始终存在一个线程,当线程意外死亡时会自动产生一个替补线程
ExecutorService threadPool = Executors.newSingleThreadExecutor();
往线程池添加任务
threadPool.executor(Runnable)
关闭线程池
threadPool.shutdown(); //线程全部空闲,没有任务就关闭线程池
threadPool.shutdownNow(); //不管任务有没有做完,都关掉
应用案例
固定大小的线程池&缓存线程池
步骤1:用3个大小的固定线程池去执行10个内部循环10次就结束的任务,为了观察固定线程池下的其他任务一直再等待,希望打印出正在执行的线程名、任务序号和任务内部的循环次数,刚开始看到只有3个线程在执行,并看到任务前仆后继的效果。注意:这10个任务要用各自独立的runnable对象,才能看到任务的序号。
步骤2:改为缓存线程池,可以看到当前有多少个任务,就会分配多少个线程为之服务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by liangyongxing on 2017/3/8.
*/
public class ExecutorPoolTest {
public static void main(String[] args) {
//ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
for (int i = 1; i <= 10; i++) { //向线程池提交10个任务
final int sequence = i;
//仔细品味runnable对象放到循环里面和外面的区别,为了让每个对象有自己独立的编号
executorService.execute(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 2; i++) {
//为了观察打印效果需要设置一定的休眠
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(String.format("%s is serving %d task loop of %d.",
Thread.currentThread().getName(), sequence, i));
}
}
});
}
/**
* 用下面这句代码来说明上面的代码是在提交任务,并且所有的任务都已经提交了,但任务是什么时候执行的,则是由线程池调度的!
*/
System.out.println("all task have committed!");
} finally {
//注意与executorService.shutdownNow()的区别。
executorService.shutdown();
}
}
}
运行线程缓冲池的打印效果如下所示: 运行固定大小线程池的打印效果如下所示:

用线程池启动定时器
a、创建调度线程池,提交任务,延迟指定时间后执行任务
Executors.newScheduledThreadPool(线程数).schedule(Runnable, 延迟时间,时间单位);
b、创建调度线程池,提交任务, 延迟指定时间执行任务后,间隔指定时间循环执行
Executors.newScheduledThreadPool(线程数). scheduleAtFixedRate (Runnable,延迟时间,间隔时间,时间单位);
所有的 schedule 方法都接受相对延迟和周期作为参数,而不是绝对的时间或日期。将以 Date 所表示的绝对时间转换成要求的形式很容易。例如,要安排在某个以后的 Date 运行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(),TimeUnit.MILLISECONDS)
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; /**
* Created by liangyongxing on 2017/3/8.
*/
public class ExexutorSchedulerTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
//这个只执行一次就完毕,不会多次执行
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("task begin running one!!!");
}}, 5, TimeUnit.SECONDS); //开始隔5s执行一次,后续每隔2s执行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("task begin running two!!!");
}}, 4, 2, TimeUnit.SECONDS);
}
}
有意将第二次间隔循环起始时间设置小于第一次循环一次的起始时间,注意:线程池初始化容量为2,则这两个定时器相当于互不影响了,则打印结果如下所示:

提示:按照JDK文档学习顺序,下一篇要讲解有关线程锁Lock,具体详情请查看我的下一篇博客:并发库应用之四 & 线程锁Lock应用
并发库应用之三 & 线程池与定时器应用的更多相关文章
- Java多线程与并发库高级应用-线程池
线程池 线程池的思想 线程池的概念与Executors类的应用 > 创建固定大小的线程池 > 创建缓存线程池 > 创建单一线程池(如何实现线程死掉后重新启动?) 关闭线程池 > ...
- PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束
PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...
- Java并发(六)线程池监控
目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...
- Java并发编程-并发工具类及线程池
JUC中提供了几个比较常用的并发工具类,比如CountDownLatch.CyclicBarrier.Semaphore. CountDownLatch: countdownlatch是一个同步工具类 ...
- <关于并发框架>Java原生线程池原理及Guava与之的补充
原创博客,转载请联系博主! 转眼快两个月没有更新自己的博客了. 一来感觉自己要学的东西还是太多,与其花几个小时写下经验分享倒不如多看几点技术书. 二来放眼网上已经有很多成熟的中文文章介绍这些用法,自己 ...
- Java并发:搞定线程池(上)
原文地址:https://www.nowcoder.com/discuss/152050?type=0&order=0&pos=6&page=0 本文是在原文的基础+理解,想要 ...
- Java 并发:Executors 和线程池
让我们开始来从入门了解一下 Java 的并发编程. 本文主要介绍如何开始创建线程以及管理线程池,在 Java 语言中,一个最简单的线程如下代码所示: Runnable runnable = new R ...
- JDK1.5中线程池,定时器知识
package cn.it.pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executo ...
- Java并发编程:Java线程池
转载自:http://www.cnblogs.com/dolphin0520/p/3932921.html 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题 ...
随机推荐
- 第十二周作业_PSP总结报告
回顾1 (1)回想一下你曾经对计算机专业的畅想 当初你是如何做出选择计算机专业的决定的?经过一个学期,你的看法改变了么,为什么? 你认为过去接触到的课程是否符合你对计算机专业的期待,为什么?经过一个学 ...
- 在写ssh项目时浏览器页面出现http status 404 – not found
HTTP Status 404 - /streetManager/index.jsp type Status report message /streetManager/index.jsp descr ...
- BugPhobia发布篇章:学霸在线系统正式发布
Alpha阶段的服务器部署和移植工作最终完成,http://10.2.26.67/,期待您的访问~ 首先,请允许bugphobia团队对您的访问给予感谢以及诚恳的致歉.受服务器端的硬件限制,目前学霸在 ...
- 2017-2018-2 1723 『Java程序设计』课程 结对编程练习_四则运算 第二周
一.结对对象 姓名:侯泽洋 学号:20172308 担任角色:驾驶员(侯泽洋) 伙伴第二周博客地址 二.本周内容 (一)继续编写上周未完成代码 1.本周继续编写代码,使代码支持分数类计算 2.相关过程 ...
- 什么是REST编程
参考:什么是REST编程:http://www.ruanyifeng.com/blog/2011/09/restful.html 一.REST是Representational State Trans ...
- HDU 5925 Coconuts 离散化
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5925 Coconuts Time Limit: 9000/4500 MS (Java/Others) ...
- 效能分析——词频统计的java实现方法的第一次改进
java效能分析可以使用JProfiler 词频统计处理的文件为WarAndPeace,大小3282KB约3.3MB,输出结果到文件 在程序本身内开始和结束分别加入时间戳,差值平均为480-490ms ...
- 我所理解的Delphi中的数组类型
数组可以使Object Pascal所拥有的任何数据类型,数组是一些数值的简单集合. var MyArray: ..] of Integer; { 声明一个数组包括5个整数数值} b ...
- 热部署在Eclipse和IDE里面的使用
热部署在Eclipse和IDE里面的使用 简介:讲解热部署的好处及使用注意事项,在eclipse里面默认开启,在IDE里面默认关闭 .增加依赖 <dependency> <group ...
- 如何处理UIVIew addsubview 不显示subview
老代码: addsubview不显示uilabel -(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSIn ...