线程池的作用主要是为了提升系统的性能以及使用率。文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可能要比处理实际业务花费的时间和性能更多。

作者:小涛

 一、如下方式存在的问题

new Thread() { @Override public void run() { // 业务逻辑 }
}.start(); 

1、首先频繁的创建、销毁对象是一个很消耗性能的事情;2、如果用户量比较大,导致占用过多的资源,可能会导致我们的服务由于资源不足而宕机;3、综上所述,在实际的开发中,这种操作其实是不可取的一种方式。

二、使用线程池有什么优点

1、线程池中线程的使用率提升,减少对象的创建、销毁;2、线程池可以控制线程数,有效的提升服务器的使用资源,避免由于资源不足而发生宕机等问题;

三、线程池的四种使用方式

1、newCachedThreadPool

创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。

public static void method() throws Exception { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { final int index = i; Thread.sleep(1000); executor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "  " + index); } }); }
} 

执行结果

可以明显的看出,现在就需要几条线程来交替执行。

不足:这种方式虽然可以根据业务场景自动的扩展线程数来处理我们的业务,但是最多需要多少个线程同时处理缺是我们无法控制的;

优点:如果当第二个任务开始,第一个任务已经执行结束,那么第二个任务会复用第一个任务创建的线程,并不会重新创建新的线程,提高了线程的复用率;

2、newFixedThreadPool

这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人同时洗澡,那么后面来的人只能在外面排队等待。如果硬往里冲,那么只会出现一种情景,摩擦摩擦...

首先测试一下最大容量为一个线程,那么会不会是我们预测的结果。

public static void method_01() throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(1); for (int i = 0; i < 10; i++) { Thread.sleep(1000); final int index = i; executor.execute(() -> { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "  " + index); }); } executor.shutdown();
} 

优点:两个结果综合说明,newFixedThreadPool的线程数是可以进行控制的,因此我们可以通过控制最大线程来使我们的服务器打到最大的使用率,同事又可以保证及时流量突然增大也不会占用服务器过多的资源。

3、newScheduledThreadPool

该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。 该线程池中有以下两种延迟的方法。

  • scheduleAtFixedRate

测试一

public static void method_02() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleAtFixedRate 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleAtFixedRate 执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleAtFixedRate 执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 5, TimeUnit.SECONDS);
} 

总结:以上两种方式不同的地方是任务的执行时间,如果间隔时间大于任务的执行时间,任务不受执行时间的影响。如果间隔时间小于任务的执行时间,那么任务执行结束之后,会立马执行,至此间隔时间就会被打乱。

  • scheduleWithFixedDelay

测试一

public static void method_03() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 2, TimeUnit.SECONDS);
} 

测试二

public static void method_03() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 2, TimeUnit.SECONDS);
} 

总结:同样的,跟scheduleWithFixedDelay测试方法一样,可以测出scheduleWithFixedDelay的间隔时间不会受任务执行时间长短的影响。

4、newSingleThreadExecutor

这是一个单线程池,至始至终都由一个线程来执行。

public static void method_04() { ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int index = i; executor.execute(() -> { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "   " + index); }); } executor.shutdown();
} 

四、线程池的作用

线程池的作用主要是为了提升系统的性能以及使用率。文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可能要比处理实际业务花费的时间和性能更多。线程池就是为了解决这种这种问题而出现的。

同样思想的设计还有很多,比如数据库连接池,由于频繁的连接数据库,然而创建连接是一个很消耗性能的事情,所有数据库连接池就出现了。

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期科技领域知识)

歌谣带你看java面试题

第二十八期:Java线程池的四种用法与使用场景相关推荐

  1. java assert使用场景_Java线程池的四种用法与使用场景

    一.如下方式存在的问题 new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1.首先频繁的创建.销毁对象是一个很消耗性能的 ...

  2. newsinglethreadexecutor使用场景_Java线程池的四种用法与使用场景

    来源公众号一个程序员的成长 ,作者小涛 一.如下方式存在的问题 new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1.首 ...

  3. Java线程池的四种创建方式

    Java线程池的四种创建方式 Java使用Thread类来表示线程,所有的线程都是Thread类或者是他的子类.Java有四种方式来创建线程. (1)继承Thread类创建线程 (2)实现Runnab ...

  4. java多线程——Executors线程池的四种用法简单解析

    1.Executors.newFixedThreadPool(5)    是创建一个线程池,池子里面有5个线程,任务数多余5个时,超出的任务队列中排队等候执行 2.Executors.newCache ...

  5. 线程池 java 新建方式_Java线程池的四种创建方式

    Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程. newFi ...

  6. 线程池概念、线程池作用、线程池的四种创建方式

    线程池 1.1.什么是线程池? 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程.线程池中线程的数量通常完全取决于可用内存数量和应用程 ...

  7. 创建线程池的四种方式_创建线程到底有几种方式?

    很多时候,在项目中使用线程的情况很少,导致很多人只停想起最常见的两种创建线程的方法,即继承Thread类和实现Runnable接口. 而网络上大家有人认为是三种实现方式,也有人认为是四种实现,下面我们 ...

  8. 线程池的四种拒绝策略

    一.前言 线程池,相信很多人都有用过,没用过相信的也有学习过.但是,线程池的拒绝策略,相信知道的人会少许多. 二.四种线程池拒绝策略 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximum ...

  9. springboot微服务实战:初探异步线程池(四种创建多线程对比)

    四种多线程对比(异步) 创建和初始化多线程的几种方式1.继承Thread2.实现Runnable接口3.实现Callable接口 + FutureTask(可以拿到返回结果,可以处理异常)4.线程池 ...

最新文章

  1. 浙大蒋超组招博后:环境暴露组和微生物组
  2. 「云网络」VS「云计算」- vecloud微云服务器
  3. 你的微信二维码是唯一的吗?【微信二维码的秘密】
  4. 让最新的 Android Q Beta 3 强制重启的 Project Mainline,到底是什么?
  5. 怎么做蒙特卡洛计算npv_计算机一级:这该死的“进制转换”,这种题到底怎么做?...
  6. 新华字典java_新华字典查询示例代码
  7. 数据特征分析-统计分析
  8. 如何用python计算levenshteindistance_Levenshtein计算相似度距离
  9. JavaScript开发中几个常用知识点总结
  10. java抽象方法特点_java-抽象类的特点
  11. Excel线性回归分析
  12. 《1024伐木累》-屌丝、快播、苍老师
  13. 如何打开VS的命令行界面
  14. 求职数据分析师岗位,简历应该如何写?|工科生三个月成功转行数据分析心得浅谈
  15. 疯子、精神病患者、诗人、哲学家、伟大的思想家—— 尼采的孤独:《最孤独者》...
  16. 【FPGA的基础快速入门31-----环境光传感器】
  17. SSM人才交流平台的开发毕业设计-附源码
  18. 对 emwin 窗口创建的认识
  19. java连接access数据库的三种方式以及远程连接
  20. 音频降噪的软件有哪些?快来看看这些软件

热门文章

  1. 详解div+css相对定位和绝对定位用法
  2. vs2008使用技巧
  3. java number string_java基础系列(一):Number,Character和String类及操作
  4. python图像对比_用python实现对比两张图片的不同
  5. linux c字符连接,C 语言实例
  6. java top.dialog控件,java – 如何只为他的父级创建JDialog onTop?
  7. 面向过程 VS 面向对象
  8. cnpm与npm的区别
  9. 微信小程序中base64转换成图片;uni-app小程序base64转图片;微信小程序base64文件转图片;微信小程序base64图片转图片
  10. React开发(265):ant design InputNumber