Executor框架的使用简介

文章转自:http://blog.csdn.net/qq_16811963/article/details/52161713

类似于我们熟悉的集合框架(由Collection和Map接口衍生出很多其他的接口和类),在JAVA多线程中,也存在一个Executor框架。等以后时间充足了,会对该框架来一波源码剖析。

简而言之,Executor框架实现了工作单元执行单元的分离。

本文用到的程序源码请参考我的github

一.Executor框架的两级调度模型

在HotSpot VM的线程模型中,JAVA线程被一对一映射为本地操作系统线程。JAVA线程启动时会启动一个本地操作系统线程:当该JAVA线程终止时,这个操作系统线程也会被回收。操作系统会调度所有线程并将它们分配给可用的CPU。

两级调度模型的示意图:

这里写图片描述

从图中可以看出,该框架用来控制应用程序的上层调度(下层调度由操作系统内核控制,不受应用程序的控制)。

二.Executor框架的结构

Executor主要由三部分组成:任务产生部分,任务处理部分,结果获取部分。(设计模式:生产者与消费者模式)

先来看个图:

这里写图片描述

1.任务的产生:Runnable接口和Callable接口

这2个对象属于任务对象。工具类Executors可以把一个Runnable对象封装为Callable对象。当我们拥有任务对象之后,就可以将其交给ExecutorService(Executor的一个实现接口)了,这样转入第二部分–任务处理部分。

2.任务的处理:Executor接口—>ExecutorService接口

任务的处理主要是将任务丢到线程池中,由线程池提供线程将任务“消费掉”。

线程池有2类:ThreadPoolExecutor和ScheduledThreadPoolExecutor。2种线程池类均可以通过工厂类Executors来创建

⑴:ThreadPoolExecutor类

工厂类可以创建3种类型的ThreadPoolExecutor类:

①:FixedThreadPool:拥有固定数量线程的线程池,限制了线程的数目,适用于负载比较重的服务器。

②:SingleThreadPool:单个线程的线程池,适用于需要保证顺序的执行各个任务;任意时间点,不会有多个线程活动。

③:CachedThreadPool:大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。

⑵:ScheduleThreadPoolExecutor类

工厂类可以创建2种类型的SchedulePoolExecutor类:

①:ScheduleThreadPoolExecutor:包含若干线程。

②:SingleThreadScheduleExecutor:单个线程。

3.任务结果的获取:Future接口

Future接口有个实现类FutureTask,迄今为止API中返回的都是FutureTask对象,未来的JDK实现中,可能有Future对象。


关于Executor框架的架构基本就这些,下面用几个Demo实测一下:

1.下面这个程序实现了启动一个2个线程的线程池并给该线程池扔入5个任务,结果显示了他们的执行策略:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
 * @author Vayne
 * 
 * Executors是线程池框架的一个工具类
 * 
 * 
 */
public class FixedThreadPoolDemo
{
    public static void main(String[] args)
    {
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // 定义一个循环,添加5个任务
        for (int i = 0; i < 5; i++)
        {
            int flag = i;
            pool.execute(new Runnable()
            {
                //任务详情:执行6次打印语句。
                @Override
                public void run()
                {
                    for(int j = 0;j<6;j++)
                    {
                        try
                        {
                            Thread.sleep(10);
                        } catch (InterruptedException e)
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+" "+flag+" "+" `s loop : "+j);
                    }
                }
            });
        }

        pool.shutdown();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

结果:

pool-1-thread-1 0  `s loop : 0
pool-1-thread-2 1  `s loop : 0
pool-1-thread-1 0  `s loop : 1
pool-1-thread-2 1  `s loop : 1
pool-1-thread-1 0  `s loop : 2
pool-1-thread-2 1  `s loop : 2
pool-1-thread-2 1  `s loop : 3
pool-1-thread-1 0  `s loop : 3
pool-1-thread-1 0  `s loop : 4
pool-1-thread-2 1  `s loop : 4
pool-1-thread-1 0  `s loop : 5
pool-1-thread-2 1  `s loop : 5           //这里2个线程将2个任务完成
pool-1-thread-1 3  `s loop : 0
pool-1-thread-2 2  `s loop : 0
pool-1-thread-2 2  `s loop : 1
pool-1-thread-1 3  `s loop : 1
pool-1-thread-2 2  `s loop : 2
pool-1-thread-1 3  `s loop : 2
pool-1-thread-2 2  `s loop : 3
pool-1-thread-1 3  `s loop : 3
pool-1-thread-2 2  `s loop : 4
pool-1-thread-1 3  `s loop : 4
pool-1-thread-1 3  `s loop : 5
pool-1-thread-2 2  `s loop : 5          //2个任务完成
pool-1-thread-1 4  `s loop : 0
pool-1-thread-1 4  `s loop : 1
pool-1-thread-1 4  `s loop : 2
pool-1-thread-1 4  `s loop : 3
pool-1-thread-1 4  `s loop : 4
pool-1-thread-1 4  `s loop : 5          //最后1个任务完成
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

下面我们再来看看CachedThreadPool的实测结果,由于代码区别只是构造方法的不同,这里不浪费页面贴代码了,直接贴出结果:

pool-1-thread-2 1  `s loop : 0
pool-1-thread-4 3  `s loop : 0
pool-1-thread-5 4  `s loop : 0
pool-1-thread-3 2  `s loop : 0
pool-1-thread-1 0  `s loop : 0    //一次开启了5个线程来承载5次任务
pool-1-thread-4 3  `s loop : 1
pool-1-thread-2 1  `s loop : 1
pool-1-thread-5 4  `s loop : 1
pool-1-thread-3 2  `s loop : 1
pool-1-thread-1 0  `s loop : 1
pool-1-thread-4 3  `s loop : 2
pool-1-thread-2 1  `s loop : 2
pool-1-thread-1 0  `s loop : 2
pool-1-thread-5 4  `s loop : 2
pool-1-thread-3 2  `s loop : 2
pool-1-thread-2 1  `s loop : 3
pool-1-thread-4 3  `s loop : 3
pool-1-thread-1 0  `s loop : 3
pool-1-thread-5 4  `s loop : 3
pool-1-thread-3 2  `s loop : 3
pool-1-thread-2 1  `s loop : 4
pool-1-thread-4 3  `s loop : 4
pool-1-thread-1 0  `s loop : 4
pool-1-thread-5 4  `s loop : 4
pool-1-thread-3 2  `s loop : 4
pool-1-thread-2 1  `s loop : 5
pool-1-thread-4 3  `s loop : 5
pool-1-thread-5 4  `s loop : 5
pool-1-thread-1 0  `s loop : 5
pool-1-thread-3 2  `s loop : 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

2.结合Future接口来做一个实测

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FutureDemo
{
    public static void main(String[] args)
    {

        ExecutorService pool = Executors.newFixedThreadPool(3);

        //CompletionService接口内部维护一个结果队列:一堆future....
        CompletionService<Integer> cs = new ExecutorCompletionService<>(pool);

        for (int i = 1; i < 11; i++)
        {
            final int flag = i * 10;
            cs.submit(new Callable<Integer>()
            {

                @Override
                public Integer call() throws Exception
                {
                    // TODO Auto-generated method stub
                    Thread.sleep(1000);
                    return flag;
                }
            });
        }

        for (int i = 0; i < 11; i++)
        {
            try
            {
                System.out.println(cs.take().get());
            } catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        pool.shutdown();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

结果:

10
20
30
50
40
60
70
90
80
100
好的,我可以为您提供一个简单的Java Executor框架使用示例。 Java Executor框架是Java SE 5引入的一个并发执行框架,它提供了一种方便的方式来管理并发任务的执行。在这个示例中,我们将使用Executor框架来执行一个简单的计算任务。 首先,我们需要定义一个实现Callable接口的任务类,该接口可以返回一个结果,并抛出一个可能发生的异常。这是一个简单的任务类示例: ``` import java.util.concurrent.Callable; public class MyTask implements Callable<Integer> { private int number; public MyTask(int number) { this.number = number; } @Override public Integer call() throws Exception { int result = 0; for (int i = 1; i <= number; i++) { result += i; } return result; } } ``` 这个任务类会计算从1到给定数字的和,并返回结果。接下来,我们需要创建一个ExecutorService,它是一个高级线程池实现,可以管理并发执行的任务。我们可以使用Executors类中的静态工厂方法来创建ExecutorService实例: ``` import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Main { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(new MyTask(10)); try { Integer result = future.get(); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } executor.shutdown(); } } ``` 在这个示例中,我们创建了一个单线程的ExecutorService,然后使用submit()方法提交了一个MyTask实例。submit()方法返回一个Future对象,我们可以使用它来检查任务是否完成,并获取任务的结果。 在这个示例中,我们使用了future.get()方法来获取任务的结果。get()方法是一个阻塞方法,它会等待任务完成并返回结果,如果任务抛出了异常,它会将异常重新抛出。因此,在调用get()方法时,我们需要使用try-catch块来处理可能抛出的异常。 最后,我们需要调用ExecutorService的shutdown()方法来关闭线程池并释放资源。这个方法会等待所有任务完成并关闭线程池,所以我们应该在使用ExecutorService后立即调用它。 这就是一个简单的Java Executor框架使用示例。希望对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值