从java5开始,类库中引入了很多新的管理调度线程的API,最常用的就是Executor(执行器)框架。Executor帮助程序员管理Thread对象,简化了并发编程,它其实就是在 提供了一个中间层,方便程序员管理异步任务的执行,而又不用显式的管理线程的生命周期。

Executor采用了线程池实现,也更节约开销,因为是我们启动新线程的首选方法。

示例代码:src/thread_runnable/CachedThreadPool.java

 public class CachedThreadPool{

     public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(); System.out.println("main start " + Thread.currentThread().getName());
for (int i=0; i<3; i++){
exec.execute(new CountDown());
} exec.shutdown();
System.out.println("main end " + Thread.currentThread().getName());
} }

输出结果:(每次执行输出结果都有差异)

Executors类通过提供一系列的工厂方法来创建线程池,返回的线程池都实现了ExecutorService接口,ExecutorService接口实现了Executor接口,提供了更丰富的方法来管理线程池,ExecutorService对象可以通过execute(Runnable)/submit(Callable)方法来开始执行新的方法(这本身也属于命令设计模式)。

ExecutorService(其实就是线程池)的生命周期包括三种状态,运行,关闭,终止。创建后便进入运行状态。调用shutdown()方法就进入关闭状态。此时ExecutorService不再接受新的任务,但是它还在执行已经提交的任务,等到所有的任务都执行完毕后,就到了终止状态。

Executors类通过提供一系列的工厂方法来创建线程池,常见类型如下:

 public static ExecutorService newFixedThreadPool(int nThreads)

创建固定数目的线程池

 public static ExecutorService newCachedThreadPool()

创建一个可缓存的线程池,调用execute添加新任务后,如果有之前构造的可用线程,则重用该线程;否则,就创建一个新线程并添加到池中。并且可以从缓存中移除那些60s未被使用的线程。

 public static ExecutorService newSingleThreadExecutor()

创建一个单线程的线程池。其实只有一个线程,所有的任务按照指定的顺序,(FIFO,LIFO,优先级)来执行。

 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个定长线程池,支持定时及周期性的任务执行,所以很多时候可用来代替Timer类。

看一个简单的例子,代码地址:src/thread_runnable/FixedThreadPool.java

 public class FixedThreadPool{
public static void main(String[] args) {
int ThreadCount = 2;
ExecutorService exec = Executors.newFixedThreadPool(ThreadCount); System.out.println("main start " + Thread.currentThread().getName());
for (int i=0; i<3; i++){
exec.execute(new CountDown());
}
exec.shutdown();
System.out.println("main end " + Thread.currentThread().getName()); }
}

当ThreadCount = 2时,某一次输出结果为:

从输出结果可以看出,在最初的时候,只有thread-1和thread-2两个线程在执行任务,当之前的任务执行完成之后,thread-2被复用,开始执行第三个任务。
那么我们可以想象,如果我们把 让ThreadCount = 1,那么应该只存在一个线程,其执行完一个任务,再接着执行另一个。
修改ThreadCount = 1,输出结果符合我们的预期:

可以周期或者delay执行的 线程也是在实际项目中也是比较常见的。
示例代码地址:src\thread_runnable\ScheduledExecutorServiceDemo.java

 public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ScheduledExecutorService mScheduledService = Executors.newScheduledThreadPool(2);
System.out.println("ScheduledExecutorServiceDemo --- main start, " + Thread.currentThread().getName());
mScheduledService.schedule(new CountDown(), 2 , TimeUnit.SECONDS);
System.out.println("ScheduledExecutorServiceDemo --- main end, " + Thread.currentThread().getName());
mScheduledService.shutdown();
}
}

输出结果:(通过实际输出,可以看到 ,两秒钟之后,才开始执行任务当中的打印 语句)

关于周期性任务的demo。
示例代码地址:src\thread_runnable\ScheduledFixedServiceDemo_2.java

 public class ScheduledFixedServiceDemo_2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ScheduledExecutorService mScheduledService = Executors.newScheduledThreadPool(2);
System.out.println("ScheduledFixedServiceDemo_2 --- main start, " + Thread.currentThread().getName());
mScheduledService.scheduleWithFixedDelay(new Runnable() {
int count = 0;
@Override
public void run() {
System.out.println("fixed print = " + count++); }
}, 1, 2 , TimeUnit.SECONDS);
System.out.println("ScheduledFixedServiceDemo_2 --- main end, " + Thread.currentThread().getName());
}
}

输出结果:

…..后面每间隔2s,输出一次。

Runnable虽然执行任务,但是没有返回值,而java 5之后 ,重新引入了一个 Callable接口,它是一个具有类型参数的泛型,表示从call()方法中返回的值。不过需要注意的是,把Callable对象传递给ExecutorService的submit方法后,在新线程上执行的call()方法返回的其实是 Future对象,Future对象有isDone(),get()等方法来判断是否完成,以及得到返回值等。

代码地址:src\thread_runnable\CallableDemo.java

 class TaskWithResult implements Callable<String> {
public String call() throws Exception {
return "result of TaskWithResult from Callable " + "\t " + Thread.currentThread().getName();
}
} public class CallableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService exec = Executors.newCachedThreadPool(); System.out.println("main start\t" + Thread.currentThread().getName());
Future<String> fs = exec.submit(new TaskWithResult());
exec.shutdown(); try {
//当callable对象并没有完成时,这里一直是堵塞的。
System.out.println(fs.get());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main end\t" + Thread.currentThread().getName());
}
}

输出结果:

这几篇java多线程文章的demo代码下载地址 http://download.csdn.net/detail/yaowen369/9786452

-------
作者: www.yaoxiaowen.com
github: https://github.com/yaowen369

java多线程(三)-Executors实现的几种线程池以及Callable的更多相关文章

  1. JAVA基础知识|Executors提供的四种线程池

    一.Thread与Executors 开启新的线程,我们经常会采用如下方法: Thread thread =new Thread(new Runnable() { @Override public v ...

  2. Java第三阶段学习(七、线程池、多线程)

    一.线程池 1.概念: 线程池,其实就是一个容纳多个线程的容器,其中的线程可以重复使用,省去了频繁创建线程对象的过程,无需反复创建线程而消耗过多资源,是JDK1.5以后出现的. 2.使用线程池的方式- ...

  3. JAVA多线程-内存模型、三大特性、线程池

    一.线程的三大特性 原子性.可见性.有序性 1)原子性,即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.原子性其实就是保证数据一致.线程安全一部分. 2)可见性,即 ...

  4. Executors创建的4种线程池的使用

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

  5. Executors提供的四种线程池和自定义线程池

    JAVA并发编程——EXECUTORS 线程池的思想是一种对象池的思想,开放一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完毕,对象 ...

  6. 多线程----Thread类,Runnable接口,线程池,Callable接口,线程安全

    1概念 1.1进程 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 任务管理器中: 1.2线程 线程是进程中的一个执行单元 ...

  7. Java多线程总结(二)锁、线程池

    掌握Java中的多线程,必须掌握Java中的各种锁,以及了解Java中线程池的运用.关于Java多线程基础总结可以参考我的这篇博文Java多线程总结(一)多线程基础 转载请注明出处——http://w ...

  8. Executors提供的四种线程池

    Java 5+中的Executor接口定义一个执行线程的工具.它的子类型即线程池接口是ExecutorService.要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,因此在工具 ...

  9. JDK提供的四种线程池代码详解

    一.线程池什么时候使用,会给我们带来什么好处? 如果很多用户去访问服务器,用户访问服务器的时间是非常短暂的,那么有可能在创建线程和销毁线程上花费的时间会远远大于访问所消耗的时间,如果采用线程池会使线程 ...

随机推荐

  1. Python 冒泡法排序

    def sequence(disorder='', separators=''): arrays = disorder.split(separators) def desc(): for i in r ...

  2. UWP 判断系统版本

    public class VersionsHelper { , ); , ); , ); , ); , ); }

  3. .NET Core快速入门教程 2、我的第一个.NET Core App(Windows篇)

    一.前言 本篇开发环境?1.操作系统: Windows 10 X642.SDK: .NET Core 2.0 Preview 二.安装 .NET Core SDK 1.下载 .NET Core下载地址 ...

  4. js 匹配2个字符串相似度

    strSimilarity2Number: function (s, t) { var n = s.length, m = t.length, d = []; var i, j, s_i, t_j, ...

  5. SSI学习(二)

    1.SSI指令 #config:指定返回到client浏览器的错误消息.日期和文件大小所使用的格式. #echo:在 HTML 页中插入环境变量的值. #exec:执行一个应用程序或一条 shell ...

  6. 重要经验五:block作为属性的注意事项

    现代ios应用的开发.不使用GCD和block,效率会减少非常多,在今年3月份之前,我在block的学习和使用方面,精力和经验都明显不足,在SF有个牛逼同事.不仅自己积累了一套库,并且对这个库持续进行 ...

  7. HDU1598 find the most comfortable road 【并查集】+【枚举】

    find the most comfortable road Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  8. 自学Zabbix3.8.1.2-可视化Visualisation-Graphs自定义图表

    自学Zabbix3.8.1.2-可视化Visualisation-Graphs自定义图表 自定义图表,如名称所示,提供定制功能.虽然简单的图形可以很好地查看单个项目的数据,但是它们不提供配置功能.因此 ...

  9. SGD

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. json小结和fastjson包的实际json操作

    工作中,需要处理与另一方系统数据交换的问题,采用的是调用远程接口的方法,数据格式选择的是json,今天就来聊一聊json,主要分析json数据和java Bean之间的转换问题. 一.json是什么 ...