在TCP服务器编程模型的原理,每一个客户端连接用一个单独的线程为之服务,当与客户端的会话结束时,线程也就结束了,即每来一个客户端连接,服务器端就要创建一个新线程。如果访问服务器的客户端很多,那么服务器要不断地创建和销毁线程,这将严重影响服务器的性能。线程池的概念与此类似,首先创建一些线程,它们的集合称为线程池,当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。

   假设如果没有线程池的话,那么就需要在run方法中不停判断,还有没有任务需要执行

线程池:先创建多个线程放在线程池中,当有任务需要执行时,从线程池中找一个空闲线程执行任务,任务完成后,并不销毁线程,而是返回线程池,等待新的任务安排。

线程池编程中,任务是提交给整个线程池的,并不是提交给某个具体的线程,而是由线程池从中挑选一个空闲线程来运行任务。一个线程同时只能执行一个任务,可以同时向一个线程池提交多个任务。

线程池创建方法

  1. 创建一个拥有固定线程数的线程池

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应用

并发库应用之三 & 线程池与定时器应用的更多相关文章

  1. Java多线程与并发库高级应用-线程池

    线程池 线程池的思想  线程池的概念与Executors类的应用 > 创建固定大小的线程池 > 创建缓存线程池 > 创建单一线程池(如何实现线程死掉后重新启动?) 关闭线程池 > ...

  2. PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束

    PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...

  3. Java并发(六)线程池监控

    目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...

  4. Java并发编程-并发工具类及线程池

    JUC中提供了几个比较常用的并发工具类,比如CountDownLatch.CyclicBarrier.Semaphore. CountDownLatch: countdownlatch是一个同步工具类 ...

  5. <关于并发框架>Java原生线程池原理及Guava与之的补充

    原创博客,转载请联系博主! 转眼快两个月没有更新自己的博客了. 一来感觉自己要学的东西还是太多,与其花几个小时写下经验分享倒不如多看几点技术书. 二来放眼网上已经有很多成熟的中文文章介绍这些用法,自己 ...

  6. Java并发:搞定线程池(上)

    原文地址:https://www.nowcoder.com/discuss/152050?type=0&order=0&pos=6&page=0 本文是在原文的基础+理解,想要 ...

  7. Java 并发:Executors 和线程池

    让我们开始来从入门了解一下 Java 的并发编程. 本文主要介绍如何开始创建线程以及管理线程池,在 Java 语言中,一个最简单的线程如下代码所示: Runnable runnable = new R ...

  8. JDK1.5中线程池,定时器知识

    package cn.it.pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executo ...

  9. Java并发编程:Java线程池

    转载自:http://www.cnblogs.com/dolphin0520/p/3932921.html 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题 ...

随机推荐

  1. 欢迎来怼--第二十九次Scrum会议

    一.小组信息 队名:欢迎来怼 小组成员 队长:田继平 成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文 小组照片 二.开会信息 时间:2017/11/17 15:55~16:25,总计30min. 地 ...

  2. 使用Spring boot 嵌入的tomcat不能启动: Unregistering JMX-exposed beans on shutdown

    新建一个spring boot的web项目,运行之后控制台输出“Unregistering JMX-exposed beans on shutdown”,tomcat也没有运行.寻找原因,看了下pom ...

  3. java 面试 -- 4

    Java面试知识点总结   本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺(阅读本文需要有 ...

  4. Software-Defined Networking A Comprehensive Survey(一)

    传统网络:1 复杂,难于管理 2 很难实现根据之前定义的方案进行配置,3 对于缺陷.变化不能够再次进行配置 4 控制和数据平面绑定在一起,使许多缺陷难于解决 SDN网络:通过打破传统网络垂直整合,从底 ...

  5. 软工实践l练习一一利用github托管项目

    这次实践的主题是在windows环境下将项目通过git将项目托管到github上.通过实践,基本掌握一些git命令的使用,在github上注册账号并学会创建repositly和organization ...

  6. POJ2823(单调队列方法解题)

    因为不太好复制,我就直接截图了,题目链接:题目大致的意思是:给一串数字,然后要你求出每k长度的连续子序列中的最大值以及最小值并输出:这题就是一个最简单的运用单调队列方法解题的例子. 解题思路:通过单调 ...

  7. MongoDB安装笔记

    2017年11月17日,在Windows Service 2008R2上成功安装MongoDB. 版本:mongodb-win32-x86_64-2008plus-ssl-3.4.6-signed.m ...

  8. Java基本程序设计结构

    一.要求: 1.设平面上有一个m×n 的网格,将左下角的网格点标记为(0,0)而右上角的网格点标记为(m,n).某人想从(0,0)出发沿网格线行进到达(m,n),但是在网格点(i,j)处他只能向上行进 ...

  9. Robot Framework 教程 (5) - 连接Oracel数据库

    Robot Framework 提供了多种Library.其中Database Library可用来连接操作数据库. 1.安装Database Library 打开Robot Framework官网, ...

  10. [转帖]overlay文件系统解析

    overlay文件系统解析 来源:http://dockone.io/article/1511 原作者: 陈爱珍 布道师@七牛云 一个 overlay 文件系统包含两个文件系统,一个 upper 文件 ...