Executor实现线程池

最近工作上需要做一个大数据量的读写操作,为了实现高效率,想到了用多线程实现。在网上查一些资料,发现在JDK 1.5之后有了一个非常方便的东东---Executor来实现多线程。

从JDK 1.5开始,增加了java.util.concurrent包,它的引入大大简化了多线程程序的开发。

java.util.concurrent包分成了三个部分,分别是java.util.concurrent、
            java.util.concurrent.atomic和java.util.concurrent.lock。内容涵盖了并发集合类、线程池机制、同步互斥机制、线程安全的变量更新工具类、锁等等常用工具。

在稍老一些的Java版本中,具体是在Java
5.0以前,启动一个任务是通过调用Thread类的start()方法来实现的,任务的提交和执行时同时进行的,如果想对任务的执行进行调度,或者想控
制同时执行的线程数量就需要额外编写代码来完成。而在Java
5.0里提供了一个新的任务执行架构使我们可以很轻松地调度和控制任务的执行。这个架构主要有三个接口和其相应的类组成。这三个接口分别是:Executor、ExevutirService和ScheduledExecutorService。下面我们来具体说明:

Executor接口

是用来执行Runnable任务的,它值定义了一个方法:

(官方文档介绍在:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html)

  execute(Runnable command):执行Ruannable类型的任务.

ExecutorService接口:ExecutorService继承了Executor的方法,并提供了执行Callable任务和中指任务执行的服务,其定义的方法主要有:

  submit(task):可用来提交Callable或Runnable任务,并返回代表此任务的Future对象

  invokeAll(collection of tasks):批处理任务集合,并返回一个代表这些任务的Future对象集合

  shutdown():在完成已提交的任务后关闭服务,不再接受新任务

  shutdownNow():停止所有正在执行的任务并关闭服务。

  isTerminated():测试是否所有任务都执行完毕了。

  isShutdown():测试是否该ExecutorService已被关闭

ExecutorService接口:

ExecutorService提供了执行任务的功能,它提供的方法主要有:

(官方文档介绍在:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html)

boolean awaitTermination(long timeout,TimeUnit unit):等待timeout设置的超时时间,如果超过了超时时间还没结束的话,就返回false,否则返回true。

    

ScheduledExecutorService接口:

在ExecutorService的基础上,ScheduledExecutorService提供了按时间安排执行任务的功能,它提供的方法主要有:

(官方文档介绍在:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledExecutorService.html)

  schedule(task, initDelay): 安排所提交的Callable或Runnable任务在initDelay指定的时间后执行

  scheduleAtFixedRate():安排所提交的Runnable任务按指定的间隔重复执行

  scheduleWithFixedDelay():安排所提交的Runnable任务在每次执行完后,等待delay所指定的时间后重复执行

它们三个都是接口,互相之间是继承关系:

ScheduledExecutorService  ==继承自=>  ExecutorService  ==继承自=>  Executor



Executors类:

虽然以上提到的接口有其实现类,但是为了方便,我们建议使用Executors的工具类来得到Executor接口的具体对象,需要注意的是,Executors是一个类,不是Executor的复数形式,Executor提供了一下一些静态方法:

(官方文档介绍在:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html)

callable(Runnable task):将一个Runnable的任务转化成callable的任务

newSingleThreadExecutor: 产生一个ExecutorService对象,这个对象只有一个线程可用来执行任务,若任务多于一个,任务将按先后顺序执行

newCachedThreadPool(): 产生一个ExecutorService对象,这个对象带有一个线程池,线程池的大小会根据需要调整,线程执行完任务后返回线程池,供执行下一次任务使用。

实例:

newFixedThreadPool(int poolSize):产生一个ExecutorService对象,这个对象带有一个大小为poolSize的线程池,若任务数量大于poolSize,任务会被放在一个queue里顺序执行

newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,若任务多于一个,任务将按先后顺序执行

newScheduledThreadPool(int poolSize): 产生一个ScheduledExecutorService对象,这个对象的线程池大小为poolSize,若任务数量大于poolSize,任务会在一个queue里等待执行

接下来我将用实例来介绍:

测试线程:

package com.yanyanblog.concurrent; 
public class TestThread implements Runnable{ 
    protected int num;
    public TestThread() {} 
    public TestThread(int num) { 
        this.num= num; 
    }
    @Override 
    public void run() { 
        System.out.print(num);          
    }    
}

Executors.newCachedThreadPool();创建corePoolSize为0,最大线程数为整型的最大数,线程keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。

实现:

package com.yanyanblog.concurrent; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
public class CachedThreadPool { 
    public static void main(String[] args) { 
        ExecutorService exec = Executors.newCachedThreadPool(); 
        for(int i = 0; i < 10; i++) { 
            exec.execute(new TestThread(i)); 
        } 
        exec.shutdown();     
    } 
}

Executors.newFixedThreadPool(int
nThreads);
创建固定大小(nThreads,大小不能超过int的最大值)的线程池

实现:

package com.yanyanblog.concurrent;
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
public class FixedThreadPool { 
    public static void main(String[] args) {
        //三个线程来执行五个任务 
        ExecutorService exec = Executors.newFixedThreadPool(3);    
        for(int i = 0; i < 5; i++) { 
            exec.execute(new TestThread(i)); 
        } 
        exec.shutdown(); 
    } 
}

Executors.newSingleThreadExecutor():创建大小为1的固定线程池。

实现:

package com.yanyanblog.concurrent; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
public class SingleThreadExecutor { 
    public static void main(String[] args) { 
        ExecutorService exec = Executors.newSingleThreadExecutor(); 
        for (int i = 0; i < 2; i++) { 
            exec.execute(new TestThread(i)); 
        } 
    } 
}

第一个任务执行完了之后才开始执行第二个任务。

总结:

1、Executors
通过这个类能够获得多种线程池的实例,例如可以调用newSingleThreadExecutor()获得单线程的ExecutorService,调用newFixedThreadPool()获得固定大小线程池的ExecutorService。拿到ExecutorService可以做的事情就比
较多了,最简单的是用它来执行Runnable对象,也可以执行一些实现了Callable<t>的对象。用Thread的start()方
法没有返回值,如果该线程执行的方法有返回值那用ExecutorService就再好不过了,可以选择submit()、invokeAll()或者
invokeAny(),根据具体情况选择合适的方法即可。

2. Atomics原子级变量
原子量级的变量,主要的类有AtomicBoolean, AtomicInteger, AotmicIntegerArray,
AtomicLong, AtomicLongArray, AtomicReference ……。这些原子量级的变量主要提供两个方法:
compareAndSet(expectedValue,
newValue):比较当前的值是否等于expectedValue,若等于把当前值改成newValue,并返回true。若不等,返回false。
getAndSet(newValue):把当前值改为newValue,并返回改变前的值。
这些原子级变量利用了现代处理器(CPU)的硬件支持可把两步操作合为一步的功能,避免了不必要的锁定,提高了程序的运行效率。

Executor实现线程池

时间: 2024-10-09 21:30:13

Executor实现线程池的相关文章

多线程-Executors和Executor,线程池

jdk1.5之前,所有的线程都是需要自己手动创建的,由jvm销毁,当请求过多的时候,频繁的创建和销毁线程是非常浪费资源的.jdk1.5为此做了优化,提供了 java.util.concurrent 包,该包下有个 Executor 接口,官方解释为: 执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建线程. 很明显,有这个这个东西,我们不需要自己手动 new Th

Executor以及线程池

在应用程序中,总是会出现大量的任务,包括相同类型的和不同类型的.要快速处理这些任务,常见方法就是利用多线程,但是也不可能为每个任务都创建一个线程,这样内存也不够,并且线程的创建销毁开销很大.最好是少量线程处理大量任务,实现线程的复用,Executor干的就是这事.程序只需要把任务提交给Executor,由Executor来确定怎么来执行这个任务,即执行策略.Executor的关闭很重要,如果Executor如果没有关闭,那JVM将无法结束.关闭方法有shutdown,shutdownNow,sh

戏(细)说Executor框架线程池任务执行全过程(上)

一.前言 1.5后引入的Executor框架的最大优点是把任务的提交和执行解耦.要执行任务的人只需把Task描述清楚,然后提交即可.这个Task是怎么被执行的,被谁执行的,什么时候执行的,提交的人就不用关心了.具体点讲,提交一个Callable对象给ExecutorService(如最常用的线程池ThreadPoolExecutor),将得到一个Future对象,调用Future对象的get方法等待执行结果就好了. 经过这样的封装,对于使用者来说,提交任务获取结果的过程大大简化,调用者直接从提交

戏(细)说Executor框架线程池任务执行全过程(下)

上一篇文章中通过引入的一个例子介绍了在Executor框架下,提交一个任务的过程,这个过程就像我们老大的老大要找个老大来执行一个任务那样简单.并通过剖析ExecutorService的一种经典实现ThreadPoolExecutor来分析接收任务的主要逻辑,发现ThreadPoolExecutor的工作思路和我们带项目的老大的工作思路完全一致.在本文中我们将继续后面的步骤,着重描述下任务执行的过程和任务执行结果获取的过程.会很容易发现,这个过程我们更加熟悉,因为正是每天我们工作的过程.除了Thr

java多线程之Executor框架线程池详细介绍与ThreadPoolExecutor

Executor框架简介 Executor框架的结构 Executor框架主要由3大部分组成: 任务: 包括被执行的任务需要实现的接口:Runable 接口.Callable接口: 任务的执行: 包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口.Executor框架有两个关键类实现了ExecutorService接口:ThreadPoolExecutor 和 ScheduledThreadPoolExecutor.ForkJoinPool

2,Executor线程池

一,Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭,可以简化并发编程的操作. Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService(异步任务),Future,Callable等. 二,Executor接口

Spring集成JavaMail并利用线程池发送邮件

我们系统存在大量发送邮件的需求,项目使用的是Spring框架而JavaMail也能很好的跟Spring进行集成,由于发送邮件最好还是使用异步进行发送,所以这里就采用线程池+JavaMail进行邮件发送,下面看具体代码实现: Step1.引入JavaMail <mail.version>1.4.7</mail.version> <dependency> <groupId>javax.mail</groupId> <artifactId>

线程池使用

1.new Thread的弊端 a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom.   c. 缺乏更多功能,如定时执行.定期执行.线程中断.相比new Thread,Java提供的四种线程池的好处在于:  a. 重用存在的线程,减少对象创建.消亡的开销,性能佳.  b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞.  c. 提供定时执行.定期执行.单线程.并发数控制

JAVA线程池的分析和使用

http://www.infoq.com/cn/articles/java-threadPool/ 1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 2. 线程池