在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. OO第三次阶段总结

    (1)调研,规格化设计的大致发展和为什么得到人类重视 结构化程序设计(英语:Structured programming),一种编程范型.它采用子程序(函数就是一种子程序).代码区块.for循环以及w ...

  2. 解决Cygwin编译cocos2dx 遇到的 error: 'UINT64_C' was not declared in this scope 问题

    环境工具:Win10.VS2013.cocos2d-x-2.2.6.Cygwin.ADT 问题来源:写了一个小游戏,VS2013上运行成功,就尝试着打包apk,项目导入到ADT里面,添加了cocos2 ...

  3. HDU 4405 Aeroplane chess 期望dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4405 Aeroplane chess Time Limit: 2000/1000 MS (Java/ ...

  4. python learning Exception & Debug.py

    ''' 在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因.在操作系统提供的调用中,返回错误码非常常见.比如打开文件的函数open(),成功时返 ...

  5. 【Leetcode】109. Convert Sorted List to Binary Search Tree

    Question: Given a singly linked list where elements are sorted in ascending order, convert it to a h ...

  6. dstat 监控时,无颜色显示

    linux:Centos 6.6 dstat:0.7.0 注意,有这个提醒:Color support is disabled, python-curses is not installed good ...

  7. Read N Characters Given Read4

    The API: int read4(char *buf) reads 4 characters at a time from a file. The return value is the actu ...

  8. java异常处理常见处理

    反例之一:丢弃异常结论一:既然捕获了异常,就要对它进行适当的处理.不要捕获异常之后又把它丢弃,不予理睬. 反例之二:不指定具体的异常 结论二:在catch语句中尽可能指定具体的异常类型,必要时使用多个 ...

  9. Class.getResourceAsStream 和 ClassLoder.getResourceAsStream 的区别

    问题描述 最近学习MyBaits时用到了 InputStream Resources.getResourceAsStream(String resource)来读取MyBatis配置文件,为了方便使用 ...

  10. BZOJ5312 冒险(线段树)

    记录区间and/or,修改时如果对整个区间影响都相同就打标记,否则递归.复杂度不太会证. #include<iostream> #include<cstdio> #includ ...