多线程管家:Executor

     明天过后,离笔者不玩网游的时间正好是两个月。窗外,很吵。笔者起身张望过去,是一对新人的结婚演出,吵吵闹闹的。

     穿着单衣,静静伫立在人群的边缘一直沉默不语。心情,凌乱。天气并非逐渐转变,是骤然间变得异常寒冷,寒气咄咄的。

     上篇,笔者创建了一个没人管的野线程,接下来笔者就给它找一个管家。

一、多线程管家:Executor简介:

    其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

    Executor允许你管理异步任务的执行,而无须显示地管理线程的生命周期。ExecutorService知道如何构建恰当的上下文来执行Runnable对象。

二、创建ExecutorService :

    第一种、CachedThreadPool会为每个传入的任务新创建一个线程
ExecutorService exec = Executors.newCachedThreadPool();
    第二种、FixedThreadPool可以一次性预先执行代价高昂的线程分配,所以可以用来限制线程的数量。这可以节省时间,因为你不必为每个任务都固定的付出创建线程的开销。
ExecutorService exeService = Executors.newFixedThreadPool(5);

三、任务附着给ExecutorService:
    有了executor,你只需要定义任务并将任务对象传递给executor即可。
exeService.execute(new Task());

四、关闭线程管家:

exeService.shutdown();

五、自定义线程工厂:

    每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,该对象将被用来创建新的线程。例如:

    package com.css.java.learning.action;

    import java.util.concurrent.ThreadFactory;

        public class Executor implements ThreadFactory {

        @Override

        public Thread newThread(Runnable run) {

            Thread thread = new Thread(run);

            return thread;

        }

    }

想使用自己定义的线程工厂
ExecutorService exec = Executors.newCachedThreadPool(new Executor());

这样可以通过具体的要求来改造线程。

六、Executor执行Runnable任务:

一旦Runnable任务传递到execute()方法,该方法便会自动在一个线程上执行。

我们引掉

搜狗截图20180923211400.png

重新加入,线程管家的概念

2222229.png

得到线程随机运行结果(这里笔者只粘贴两个了):

结果1:

结果.png


结果2:

结果2.png

七、线程返回值:

    前面我们讲任务实现Runnable,该接口的run方法并无返回值。

而我们,却想知道,任务执行的怎么样了:成功、失败、失去响应、正在进行?

那么我们就需要用到Callable的call方法,它可以根据你传入的泛型参数返回对应类型的数据。

这里我们重新创建一个任务:

callable2.png

来一个相对复杂一点点的,线程池

package com.css.java.learning.action;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class Thread1 {

public static void main(String[] args) {

ExecutorService executorService = Executors.newCachedThreadPool();   

    /*Future将来的结果。那么在获取该类型存放的线程运行结果时,可能该线程并未运行完毕,所以称其为“将来的结果”。
    首先,可以用isDone()方法来查询Future是否已经完成,任务完成后,可以调用get()方法来获取结果
    如果不加判断直接调用get方法,此时如果线程未完成,get将阻塞,直至结果准备就绪

    */

     List<Future<String>> resultList = new ArrayList<Future<String>>();   

       //创建10个任务并执行   

       for (int i = 0; i < 10; i++){   

           //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中   

           Future<String> future = executorService.submit(new Task3Callable(i));   

           //将任务执行结果存储到List中   

           resultList.add(future);   

       }   

       //遍历任务的结果   

       for (Future<String> fs : resultList){   

               try{   

                   while(!fs.isDone());//Future返回如果没有完成,则一直循环等待,直到Future返回完成  

                   System.err.println(fs.get());//打印各个线程(任务)执行的结果

               }catch(InterruptedException e){   

                   e.printStackTrace();   

               }catch(ExecutionException e){   

                   e.printStackTrace();   

               }finally{   

                   //启动一次顺序关闭,执行以前提交的任务,但不接受新任务  

                   executorService.shutdown();   

               }   

       }   

}

}

运行结果:

callable结果.png

我们可以看出:

1、submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。

2、如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。

八、用ThreadPoolExecutor类自定义线程池:

        //创建等待队列   

        BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);   

        //创建线程池,池中保存的线程数为3,允许的最大线程数为5  

        ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue);   

        //创建四个任务   

        Runnable t1 = new Task1(2);   

        Runnable t2 = new Task2();   

        Runnable t3 = new Task2();   

        Runnable t4 = new Task2();   

        //每个任务会在一个线程上执行  

        pool.execute(t1);   

        pool.execute(t2);   

        pool.execute(t3);   

        pool.execute(t4);   

        //关闭线程池   

        pool.shutdown();   


爱的速递所大多多.png

猜你喜欢

转载自blog.51cto.com/13479739/2276276