先来看下ThreadPool的类结构

其中红色框住的是常用的接口和类(图片来自:https://blog.csdn.net/panweiwei1994/article/details/78617117?from=singlemessage)

为什么需要线程池呢?
我们在创建线程的时候,一般使用new Thread(),但是每次在启动一个线程的时候就new 一个Thread对象,会让性能变差(spring不都使用IOC管理对象了嘛)。还有其他的一些弊端:

  • 可能会造成无限创建线程对象,对象之间相互竞争资源,造成过多占用资源而宕机。
  • 缺乏相关功能,如定时执行、定期执行、线程中断。

使用线程池的避免这些事情:

  • 重用存在的线程,减少对象创建、消亡的开销,性能佳。
  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  • 提供定时执行、定期执行、单线程、并发数控制等功能。

线程池的种类:
java通过Executor是提供4种线程池,分别为:
1)newCachedThreadPool:创建一个可缓存的线程池,有任务来临时如果线程池中有空闲的线程,那么就使用空闲的线程执行任务(即线程是可以复用),如果没有空闲线程则创建新的线程执行任务。
2)newFixedThreadPool:创建一个定长的线程池,线程池的线程数量固定,当任务来临,但是又没有空闲线程,则把任务放入队列中等待直到有空闲线程来处理它。
3)newScheduledThreadPool:创建一个定长的线程,但是能支持定时或周期性的执行。
4)newSingleThreadPool:创建一个单线程化的线程池,线程池中只有一个唯一的线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。

示例:
1)newCachedThreadPool

 /**
* 创建可缓存的线程池,线程池的线程可以重复利用,除非任务来不及处理就会创建新的线程。
*/
public static void createCachedThreadPool(){
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
//在这里使主线程停下来,让启动的线程执行完Syso操作
//并且有时间回收线程以确保下次启动的线程还是上次的线程
Thread.sleep(index * 1000);//
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
/* try {
//这里让启动的线程睡眠,保证下次启动的线程是新的线程,不是此时睡眠的。
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
System.out.println(Thread.currentThread().getName() + " " + index);
}
}); }
}

执行结果:

结果显示,执行for循环输出的线程都是同一个,线程重复使用了。

把注释的地方放开,并且注释上面的睡眠,执行结果:

结果显示的是不同的线程名称执行的for循环,对比上面的执行结果的线程名称,可以得出结论:有任务来临时如果线程池中有空闲的线程,那么就使用空闲的线程执行任务(即线程是可以复用),如果没有空闲线程则创建新的线程执行任务。

2)newFixedThreadPool

  /**
* 创建固定长度的线程池,超出的任务会在队列中进行等待,直到有线程空出来来执行。
*/
public static void createFixedThreadPool() {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "," + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}

运行结果:

创建了固定长度是3的线程池,输出前3行之后,发现线程都在sleep(),要执行的输出任务没有找到对应的执行线程,任务就会放入队列中进行等待,等待某个线程执行完毕后,再去执行任务。(线程池中的线程也是重复使用的)

3)newScheduledThreadPool

3.1)延迟执行某个线程

 public static void createScheduledThreadPoolToDelay(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
for(int i = 0; i < 10; i++){
final int index = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduledThreadPool.schedule(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " " + index + " delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}

执行结果:

延迟3+2秒执行(3秒是newScheduledThreadPool中设置的,2秒是Thread.sleep()设置的),结果中可以看出主线程睡眠2秒并不能保证newScheduledThreadPool线程池中是使用旧线程执行任务还是新建线程执行任务,这种情况是随机的。(这点和newCachedThreadPool不一样,newCachedThreadPool是用就线程)

3.2)定期执行某个任务

  public static void createScheduledThreadPoolToFixRate(){
ScheduledExecutorService exe = Executors.newScheduledThreadPool(3);
exe.scheduleAtFixedRate(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS); }

执行结果:

结果是延迟1s启动线程,并且之后每隔3s重复执行任务,但是用的是同一个线程。

4)newSingleThreadPool

 /**
* 创建一个单线程的线程池
*/
public static void createSingleThreadPool(){
ExecutorService exe = Executors.newSingleThreadExecutor();
for(int i = 0; i < 10; i++){
final int index = i;
exe.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + ", " +index);
Thread.sleep(2000);// 让当前线程睡眠2s,发现顺序打印1~10,并且有个打印停顿2s
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}

运行结果:

每输出一行结果就等待2s,可以看出每次输出的线程名都一样,说使用的同一个线程。单线程化的线程池中只有一个线程。

总结:
上面就是4中线程池的实现及其使用示例,和他们之间的区别。

其中newFixedThreadPool()有个坑,最好不要使用Executor.newFixedThreadPool(int nThreads)来创建线程池,因为它使用了LinkedBlockingQueue,容量是Integer.MAX_VALUE,容量太大容易造成防止所有任务都被阻塞,从而导致死锁。下面是具体源码:

   public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
    /**
* Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}

应该尽量直接使用new ThreadPoolExecutor来创建线程池,并指定阻塞队列的容量。

参考文章:https://www.cnblogs.com/zhaoyan001/p/7049627.html

Java中java.util.concurrent包下的4中线程池代码示例的更多相关文章

  1. java.util.concurrent包下集合类的特点与适用场景

    java.util.concurrent包,此包下的集合都不允许添加null元素 序号 接口 类 特性 适用场景 1 Queue.Collection ArrayBlockingQueue 有界.阻塞 ...

  2. Java并发编程之java.util.concurrent包下常见类的使用

    一,Condition 一个场景,两个线程数数,同时启动两个线程,线程A数1.2.3,然后线程B数4.5.6,最后线程A数7.8.9,程序结束,这涉及到线程之间的通信. public class Co ...

  3. java.util.concurrent包下并发锁的特点与适用场景

    序号 类 备注 核心代码 适用场景 1 synchronized 同步锁 并发锁加在方法级别上,如果是单例class对象,则只能允许一个线程进入public synchronized void doX ...

  4. Java并发机制(8)--concurrent包下辅助类的使用

    Java并发编程:concurrent包下辅助类的使用 整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920397.html 1.CountDown ...

  5. Java中多线程的使用(超级超级详细)线程池 7

    Java中多线程的使用(超级超级详细)线程池 7 什么是线程池? 线程池是一个容纳多个线程的容器,线程池中的线程可以重复使用,无需反复创建线程而消耗过多的资源 *使用多线程的好处: 1.降低消耗,减少 ...

  6. java.util.concurrent包

    在JavaSE5中,JUC(java.util.concurrent)包出现了 在java.util.concurrent包及其子包中,有了很多好玩的新东西: 1.执行器的概念和线程池的实现.Exec ...

  7. java.util.concurrent包API学习笔记

    newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...

  8. 【并发编程】【JDK源码】JDK的(J.U.C)java.util.concurrent包结构

    本文从JDK源码包中截取出concurrent包的所有类,对该包整体结构进行一个概述. 在JDK1.5之前,Java中要进行并发编程时,通常需要由程序员独立完成代码实现.当然也有一些开源的框架提供了这 ...

  9. 高并发编程基础(java.util.concurrent包常见类基础)

    JDK5中添加了新的java.util.concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法 ...

随机推荐

  1. robot framework---校验新增条数功能

    check总条数验证 [Arguments] ${beforevalue} ${endvalue} ${value} ${a} Evaluate '${beforevalue}'.replace('共 ...

  2. mysql用户管理和pymysql模块

    一:mysql用户管理 mysql是一个tcp的服务器,用于操作服务器上的文件数据,接收用户端发送的指令,而接收指令时就 需要考虑安全问题. 在mysql自带的数据库中有4个表是用于用户管理的,分别是 ...

  3. Unity3d外包—就找北京动点软件(长年承接Unity3d软件、游戏项目外包)

    承接Unity3d体感企业项目.游戏项目外包 北京公司.专业团队,成员为专业Unity3d产品公司一线开发人员,有大型产品开发经验: 提供优质的售后服务,保证产品质量,轻量级产品可以提供规范清晰的源代 ...

  4. virtual box centos7 common operation

    ======= network part =======1.设置桥接模式 2.vi /etc/sysconfig/network-scripts/ifcfg-enp0s3BOOTPROTO=stati ...

  5. springboot缓存注解——@Cacheable和@CacheConfig

    @Caching :制定多个缓存规则 @Cacheable 和 @CachePut 同时标注时 ,@CachePut导致还是会走方法跟数据库交互 //根据lastName查,并将结果缓存,并且可以用于 ...

  6. win2008 401 - 未授权: 由于凭据无效,访问被拒绝。解决方法

    iiis中一个小配置的问题,“身份验证”里面“启用匿名身份验证”,编辑匿名身份验证凭据,选中下面的“应用程序池标识”  就可以了

  7. vue中<select>绑定事件

    <div id="app"> <select v-model="selectItem" @change="selectFn($eve ...

  8. webpack打包vue项目,资源路径如何从绝对路径改为相对路径?css中的图片资源如何修改配置?

    资源相对引用路径 问题描述 一般情况下,通过webpack+vuecli默认打包的css.js等资源,路径都是绝对的. 但当部署到带有文件夹的项目中,这种绝对路径就会出现问题,因为把配置的static ...

  9. Project中最常用的注意点

    最近用Project 2013做计划,做工作量的评估,感觉确实牛逼得一塌糊涂.这几天自己试着做一些手工的计算,与Project的结果进行对比,发现学到的很多东西,网上确实很难道到,花了几天的时间研究, ...

  10. 利用itext将html页面转成pdf(不模糊)

    1.maven项目进入依赖 <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId> ...