在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. 互评Alpha作品——Hello World!团队作品空天猎

    基于NABCD评论作品 1.Need需求:市面上同类型的手机及PC端飞行射击类游戏有很多,所以从需求方面来说,这款游戏的潜在客户非常有局限性.近些年较火的飞行射击类游戏,例如腾讯14年发行的<全 ...

  2. psp报告

    1.读材料回答问题 (1)回想一下你曾经对计算机专业的畅想.当初你是如何做出选择计算机专业的决定的?你认为过去接触到的课程是否符合你对计算机专业的期待,为什么?你觉得计算机是你喜欢的领域吗,它是你擅长 ...

  3. 实验五 Java网络编程及安全 实验报告 20135232王玥

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序与设计         班级:1352 姓名:王玥 学号:20135232 成绩:             指导 ...

  4. 现代软件工程构建之法 前五章阅读感想&困惑

    第一章 第一节 新时代中国的IT产业市场规则不规范,书中提到社会上有个别软件公司的软件一定要卸载别家公司的软件才能运行,我这里感到疑惑---————是不是说如果 一间软件公司他能做出一个像微软操作系统 ...

  5. bootstrap使用总结

    bootstrap是一个webcss框架,集合了html/css/jquery为一家,创建响应式的页面.所谓的响应式就是适配不同的上网设备. 使用bootstrap的步骤: 1.下载bootstrap ...

  6. LeetCode题解:(221) Maximal Square

    题目说明 Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's a ...

  7. PAT 甲级 1151 LCA in a Binary Tree

    https://pintia.cn/problem-sets/994805342720868352/problems/1038430130011897856 The lowest common anc ...

  8. vue开发完成后打包后图片路径不对

    用vue做了一个小的移动端项目,从头到尾做下来,感觉自己好多东西都没弄清楚过.也学到了很多,已整理笔记在自己电脑上,但是比较零散,空了再来仔细整理整理. 于是,上周五模拟好数据(接口还未写),准备打包 ...

  9. soap 简单的例子

    首先确保你的soap模块开启 客户端代码 <?php try { $client = new SoapClient(null, array('location' =>"http: ...

  10. [转贴]Linux的SUID SGID 等知识内容

    作者:sparkdev 出处:http://www.cnblogs.com/sparkdev/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接, ...