Executor框架

Java的线程既是工作单元,也是执行机制。JDK5开始,把工作单元和执行机制分离开,工作单元包括RunnableCallable,而执行机制由Executor框架提供。

Executor框架简介

Executor框架的结构和成员

  • Executor框架的结构:主要由下面3部分组成。

    • 任务:被执行的任务需要实现Runnable接口或Callable接口。
    • 任务的执行:包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口(ThreadPoolExecutorScheduledThreadPoolExecutor)。
    • 异步计算的结果:包括接口Future和实现Future接口的FutureTask类。
  • 主要的类和接口

    • Executor是一个接口,是Executor框架的基础,它将任务的提交和任务的执行分离开来。
    • ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务。
    • ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。ScheduledThreadPoolExecutorTimer更灵活,功能更强大。
    • Future接口和实现Future接口的FutureTask类,代表异步计算的结果。
    • RunnableCallable接口的实现类,具体执行任务的类。
  • Executor框架的成员
    介绍Executor框架的主要成员:ThreadPoolExecutorScheduledThreadPoolExecutorFuture接口、Runnable接口、Callable接口、Executors

    • ThreadPoolExecutor通常使用工厂类Executors来创建。有3中类型。
      • FixedThreadPool:创建使用固定线程数的。适用于需要限制当前线程数量的应用场景。
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
* `SingleThreadExecutor`:创建单个线程。
public static ExecutorService newSingleThreadExecutor()
* `CachedThreadPool`:大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。

corePoolSize为0,maximumPoolSizeInteger.MAX_VALUE,工作队列为SynchronousQueue。会出现极端情况,即用户提交任务速度高于线程处理任务速度,会不断的创建新线程,直到耗尽CPU和内存。每个线程在结束任务60s之后,会被终止。

  • ScheduledThreadPoolExecutor通过工厂类Executor来创建,有2种类型。

    • ScheduledThreadPoolExecutor:包含若干个线程的ScheduledThreadPoolExecutor
    • SingleThreadScheduledExecutor:只包含一个线程的ScheduledThreadPoolExecutor
  • Future接口
    使用submit提交的时候,会返回一个实现Future接口的对象。

  • Runnable接口和Callable接口
    都可以被ThreadPoolExecutor执行,区别是Runnable接口不会返回结果,而Callable接口可以返回结果。
    可以把一个Runnable对象包装成一个Callable对象。

public static Callable<Object> callable(Runnable task)
//当任务执行结束,Future.get()得到null
public static <T> Callable<T> callable(Runnable task, T result))
//当任务执行结束,Future.get()得到result对象。

ScheduledThreadPoolExecutor 详解

主要用来在给定的延迟之后运行任务,或者定期执行任务。ScheduledThreadPoolExecutor的功能和Timer类似,但ScheduledThreadPoolExecutor功能更强大灵活,对应过个后台线程,Timer对应的是单个后台线程。

运行机制

  • 调用ScheduledThreadPoolExecutorscheduleAtFixedRate()或者scheduleWithFixedDelay()方法是,会向ScheduledThreadPoolExecutorDelayQueue添加一个实现了RunnableScheduledFutur接口的ScheduledFutureTaskDelayQueue是无界的,所以maximunPoolSize无效。DelayQueue只能获取到时间已经到期的元素。
  • 线程池中的线程从DelayQueue种获取ScheduledFutureTask,然后执行任务。

ScheduleFutureTask主要包含3个成员变量:

  • long型成员变量time,表示这个任务将要执行的具体时间。
  • long型成员变量sequenceNumber,表示这个任务在线程池中的序号。
  • long型成员变量period,表示任务执行的间隔周期。

FutureTask详解

Future接口和实现Future接口的FutureTask类,代表异步计算的结果。

FutureTask的使用

可以把FutureTask交给Executor执行;也可以通过ExecutorService.submit(...)方法返回一个FutureTask,然后执行FutureTask.get()方法或者FutureTask.cancel(...)方法。除此以外,还可以单独使用FutureTask

package com.future;

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class TutureTaskTest {
    private final ConcurrentMap<Object, Future<String>> taskCache = new ConcurrentHashMap<Object, Future<String>>();
    private String executionTask(final String taskName) throws ExecutionException, InterruptedException{
        while(true){
            Future<String> future = taskCache.get(taskName);
            if(future == null){//没有该任务
                Callable<String> task = new Callable<String>(){
                    @Override
                    public String call() throws Exception {
                        return taskName;
                    }
                };
                //创建任务
                FutureTask<String> futureTask = new FutureTask<String>(task);
                future = taskCache.putIfAbsent(taskName, futureTask);//如果这个key不存在就put返回null,否则不put并返回以前的值。
                if(future == null){//put成功返回null
                    future = futureTask;
                    futureTask.run();//此次新添加了这个任务,执行这个任务
                }
            }
            try{
                return future.get();//等待该线程执行完任务之后返回
            }catch(CancellationException e){
                taskCache.remove(taskName, future);
            }
        }
    }
    public static void main(String[] args) {
        
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容