JAVA语言内置了多线程的支持:1. 但是创建线程需要操作系统的资源(例如线程本身的资源,栈的空间等等)2. 如果我们频繁的创建和销毁线程,就需要消耗大量的时间.

如果我们可以复用一个线程,假如我们有大量的小任务,我们就可以让它们排队执行,然后在一个线程池里,由少量的线程执行大量的任务.
线程池:1. 所以线程池可以维护若干个线程,让他们处于等待状态.2. 如果有新任务,就分配一个空闲的线程来执行这个任务.3. 如果所有的线程都处于忙碌状态,新任务就放入队列等待.

ExecutorService来表示一个线程池,我们通常使用ExecutorService的静态方法,比如newFixedThreadPool来创建一个固定大小的线程池,然后我们通过一个submi()方法提交一个任务JDK提供的常用的ExecutorService包括:1. FixedThreadPool: 线程数固定的线程池2. CachedThreadPool: 线程数根据任务动态调整的线程池3. SingleThreadExecutor: 这个线程池只包含一个线程,也就是所有的任务只能以单线程的形式执行
package com.leon.day05;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// PrintTask继承自Runnable
class PrintTask implements Runnable {String name;public PrintTask(String name) {this.name = name;}@Overridepublic void run() {// run方法中我们执行多次,大概需要3秒钟for(int i=0;i<3;i++) {System.out.println("Hello, " + name  + "!");try {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}finally {}}}}public class ThreadPool {public static void main(String[] args) throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(3);executor.submit(new PrintTask("Bob"));executor.submit(new PrintTask("Alice"));executor.submit(new PrintTask("Tim"));executor.submit(new PrintTask("Robot"));Thread.sleep(100);executor.shutdown();}}
package com.leon.day05;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// PrintTask继承自Runnable
class PrintTask implements Runnable {String name;public PrintTask(String name) {this.name = name;}@Overridepublic void run() {// run方法中我们执行多次,大概需要3秒钟for(int i=0;i<3;i++) {System.out.println("Hello, " + name  + "!");try {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}finally {}}}}public class ThreadPool {public static void main(String[] args) throws InterruptedException {// 我们改成SingleThreadPool// 这个时候我们发现所有的任务都是以串行的方式执行的,因为我们的线程池里面只有一个线程ExecutorService executor = Executors.newSingleThreadExecutor();executor.submit(new PrintTask("Bob"));executor.submit(new PrintTask("Alice"));executor.submit(new PrintTask("Tim"));executor.submit(new PrintTask("Robot"));Thread.sleep(100);executor.shutdown();}}
package com.leon.day05;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// PrintTask继承自Runnable
class PrintTask implements Runnable {String name;public PrintTask(String name) {this.name = name;}@Overridepublic void run() {// run方法中我们执行多次,大概需要3秒钟for(int i=0;i<3;i++) {System.out.println("Hello, " + name  + "!");try {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}finally {}}}}public class ThreadPool {public static void main(String[] args) throws InterruptedException {// 我们再改成CachedThreadPool,由于CachedThreadPool会根据我们的任务动态的调整线程的数量// 所以这四个任务提交进去以后,线程池会立刻创建四个线程,// 如果我们想要限制线程池的上限,最多10个线程,ExecutorService executor = Executors.newCachedThreadPool();executor.submit(new PrintTask("Bob"));executor.submit(new PrintTask("Alice"));executor.submit(new PrintTask("Tim"));executor.submit(new PrintTask("Robot"));Thread.sleep(100);executor.shutdown();}}
    public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}cachedThreadPool的源码,实际上就是一个ThreadPoolExecutor的实例,我们可以复制一下代码.第一个参数是corePoolSize,第二个参数maximunPoolSize线程池最大的大小,我们可以把第二个参数调整为10
package com.leon.day05;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;// PrintTask继承自Runnable
class PrintTask implements Runnable {String name;public PrintTask(String name) {this.name = name;}@Overridepublic void run() {// run方法中我们执行多次,大概需要3秒钟for(int i=0;i<3;i++) {System.out.println("Hello, " + name  + "!");try {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}finally {}}}}public class ThreadPool {public static void main(String[] args) throws InterruptedException {// 这里就是10个线程的线程池ExecutorService executor = new ThreadPoolExecutor(0, 10,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());executor.submit(new PrintTask("Bob"));executor.submit(new PrintTask("Alice"));executor.submit(new PrintTask("Tim"));executor.submit(new PrintTask("Robot"));Thread.sleep(100);executor.shutdown();}}
JDK还提供了一个ScheduledThreadPool1. 它可以把一个任务定期的反复的执行ScheduledThreadPool他又两种执行模式

一种是 Fixed Rate一种是 Fixed DelayFixed Rate 是指在固定的间隔任务就会执行,例如每隔三秒钟任务就会启动,而不管任务到底执行了多长时间.Fixed Delay 是指任务执行完毕以后,我们等待一秒钟,再接着执行.无论任务执行多久,只有在任务执行结束以后,等待一秒钟,才会执行下一次的任务.
package com.leon.day05;import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 在HelloTask中打印两行语句,然后中间间隔1秒钟* 所以执行这个任务大概需要一秒* @author Leon.Sun**/
class HelloTask implements Runnable {String name;public HelloTask(String name) {this.name = name;}@Overridepublic void run() {System.out.println("Hello, " + name + "! It is " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Goodbye, " + name + "! It is " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}}public class Schedule {public static void main(String[] args) {// 先创建一个Schedule的ExecutorService,然后提交两个任务ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);// 第一个任务我们以FixedRate的模式执行,2表示两秒以后执行,参数5表示每隔5秒执行这个任务executor.scheduleAtFixedRate(new HelloTask("Bob"), 2, 5, TimeUnit.SECONDS);// 第2个任务我们以fixedDelay来运行,参数2表示我们会在2秒以后来执行,参数5表示间隔是5秒钟executor.scheduleWithFixedDelay(new HelloTask("Alice"), 2, 5, TimeUnit.SECONDS);}}由于Schedule的ThreadPool不会自动停止,所以我们强制结束虚拟机我们观察执行的结果,我们可以看到Hello Bob的会执行的比较快,每隔5秒钟就会执行,而Hello Alice这个任务,它执行的任务会比较低,因为它会间隔5秒钟才会执行

1. 我们使用ScheduledThreadPool会有一个问题,在FixedRate模式下,如果执行的任务时间过长,后续的任务会不会导致并发执行呢?2. 如果任务抛出了异常,后续任务是否还是继续执行呢?大家可以通过代码简单的验证一下
JDK还提供了一个java.util.Timer的类这个类也可以定期的执行一个任务1. 一个Timer类只会对应一个Thread类,所以只会定期执行一个任务2. 如果我们要执行多个定期任务,就必须启动多个Timer,而一个ScheduledThreadPool就可以调度多个任务所以我们现在完全可以使用ScheduledThreadPool取代旧的Timer类
1. JDK提供的ExecutorService实现了线程池的功能2. 线程池内部维护一组线程,可以高效执行大量的小任务3. Executors提供了静态方法创建不同类型的ExecutorService4. 必须调用shutdown()关闭ExecutorService5. ScheduleThreadPool可以定期调度多个任务

但是这里我们提交一个Task,因为它继承自Runnable

因此JDK又提供了一个Callable接口

我们可以把一个Callable的Task交给Executor异步执行,当我们实现Callable接口的时候,我们需要实现一个泛型接口,例如我们期望的返回值是一个String,我们就写Callable<String>,我们要复写call方法

我们如何获取一个异步执行的结果呢?当我们提交一个Callable的任务以后,我们会获得一个Future<String>对象,然后我们在主线程的某个时刻调用future对象的get()方法,如果异步结果完成,我们就直接获得结果,如果异步任务还没有完成,那么get方法会阻塞,直到任务完成以后才会有结果.

Future接口表示未来可能会返回的结果,通过get方法返回一个异步返回的结果cacel方法会终止一个异步任务的执行,isDone()方法可以判断当前的异步任务是否已经完成.
package com.leon.day05;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** 有一个Callable接口* @author Leon.Sun**/
class DownloadTask implements Callable<String> {String url;public DownloadTask(String url) {this.url = url;}// 我们复写call方法public String call() throws Exception {System.out.println("Start download " + url + "...");URLConnection conn = new URL(this.url).openConnection();conn.connect();try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) {String s = null;StringBuilder sb = new StringBuilder();while ((s = reader.readLine()) != null) {sb.append(s).append("\n");}return sb.toString();}}
}public class Main {public static void main(String[] args) throws Exception {// 我们先创建一个ExecutorExecutorService executor = Executors.newFixedThreadPool(3);// 我们可以下载一个指定URL的网页// 我们创建一个DownloadTask,传入一个URLDownloadTask task = new DownloadTask("http://www.baidu.com/");// 最后我们把下载好的网页以String的方式返回// 我们提交这个任务Future<String> future = executor.submit(task);// 然后通过future的get方法获得String html = future.get();System.out.println(html);// 关闭这个线程池executor.shutdown();}
}

当我们不需要返回结果的时候,我们可以提交一个Runnable的任务,如果我们需要一个返回结果的任务的时候我们就提交一个Callable的任务
1. 提交一个Callable的任务,可以获得一个Future对象2. 可以用Future在将来某个时刻获取结果

ExecutorService- Future - Java多线程编程相关推荐

  1. Java多线程编程中Future模式的详解

    转载自 https://www.cnblogs.com/winkey4986/p/6203225.html Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker ...

  2. Java 多线程编程核心技术

    课程介绍 多线程编程在最大限度利用计算资源.提高软件服务质量方面扮演着至关重要的角色,而掌握多线程编程也成为了广大开发人员所必须要具备的技能. 本课程以基本概念.原理方法为主线,每篇文章结合大量演示实 ...

  3. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  4. java多线程编程同步方法_实践【Java多线程编程核心技术】系列:同步方法造成的无限等待...

    本文实践来自于[Java多线程编程核心技术]一书! 同步方法容易造成死循环,如-- 类Service.java: package service; public class Service { syn ...

  5. java超线程_超线程多核心下Java多线程编程技术分析

    在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述超线程多核心下Java多线程编程技术分析,更多Java专业知识,广州疯狂 ...

  6. Java多线程编程实战指南

    内容简介 随着CPU 多核时代的到来,多线程编程在充分利用计算资源.提高软件服务质量方面扮演了越来越重要的角色.而解决多线程编程中频繁出现的普遍问题可以借鉴设计模式所提供的现成解决方案.然而,多线程编 ...

  7. Java多线程编程实战指南+设计模式篇pdf

    下载地址:网盘下载 随着CPU 多核时代的到来,多线程编程在充分利用计算资源.提高软件服务质量方面扮演了越来越重要的角色.而 解决多线程编程中频繁出现的普遍问题可以借鉴设计模式所提供的现成解决方案.然 ...

  8. Java多线程编程那些事:volatile解惑--转

    http://www.infoq.com/cn/articles/java-multi-thread-volatile/ 1. 前言 volatile关键字可能是Java开发人员"熟悉而又陌 ...

  9. Java多线程编程模式实战指南(二):Immutable Object模式--转载

    本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-o ...

  10. java多线程编程_Java多线程编程实战指南+设计模式篇.pdf

    Java多线程编程实战指南+设计模式篇.pdf 对Java架构技术感兴趣的工程师朋友们可以关注我,转发此文后私信我"Java"获取更多Java编程PDF资料(附送视频精讲) 关注我 ...

最新文章

  1. Macbook 无法找到Centos启动盘问题解决
  2. 作为前端开发兼任产品专员是一种咋样的体验
  3. 程序员日常工作中如何正确的偷懒?
  4. mongo数据库 备份 还原
  5. transpose公式_EXCEL转置你是用公式还是选择性粘贴?
  6. 二维数组 类型_Java第六章 | 二维数组的创建及使用、数组排序算法
  7. C++利用栈实现计算器
  8. react-native 报错 RawText must be wrapped in an explicit Text component
  9. Ext.Net系列:二Event之DirectEvent 示例2(Delay)
  10. 【React Native 安卓开发】----(Flexbox布局)【第二篇】
  11. 改变win7登陆时的界面
  12. Java怎么学?分享6个学习窍门
  13. 转 波束成形 Beamforming 简述
  14. Amazon alexa skill开发中遇到的坑
  15. 文字竖直居中 html,CSS 文字垂直居中
  16. Ubuntu 修改中文字体教程
  17. 七段显示器显示整数C语言答案,C语言程序设计试卷(含答案)(7页)-原创力文档...
  18. 计算机垃圾回收站内容怎么恢复,回收站的文件怎么恢复_回收站文件清空了怎么恢复-win7之家...
  19. 10款手机网页模板_手机wap网站模板_html5手机网站模板源码下载(三)
  20. 基于laravel免费开源CMS推荐

热门文章

  1. Oracle备份恢复之逻辑备份
  2. Javascript的变量作用域居然可以跨越多个函数!
  3. aliyun 阿里云Maven仓库地址 不管是自建私服还是maven构建 必备 结束了几kb的历史
  4. 【echarts】echarts开发详解
  5. CommandLineRunner与ApplicationRunner接口的使用及源码解析
  6. 2.Android 学习之虚拟机安装
  7. linux文件读写 文件锁、select、poll【转】
  8. 第一次打开Lightroom时的基本设置
  9. 当INPUT 连续输入是连续触发
  10. 网站外链数量的变化可以从哪几点去理解