线程池+ Callable 的基本使用

线程池的作用

    1、减少线程创建与切换的开销

  • 在没有使用线程池的时候,来了一个任务,就创建一个线程,我们知道系统创建和销毁工作线程的开销很大,而且频繁的创建线程也就意味着需要进行频繁的线程切换,这都是一笔很大的开销。

    2、控制线程的数量

  • 使用线程池我们可以有效地控制线程的数量,当系统中存在大量并发线程时,会导致系统性能剧烈下降。

    3、循环利用有限的线程

  • 线程池中会预先创建一些空闲的线程,他们不断的从工作队列中取出任务,然后执行,执行完之后会继续执行工作队列中的下一个任务,减少了创建和销毁线程的次数,每个线程都可以一直被重用,节省创建和销毁的开销。

线程池的使用

    常用Java线程池本质上都是由ThreadPoolExecutor或者ForkJoinPool生成的,只是其根据构造函数传入不同的实参来实例化相应线程池而已。

(1)Executors是一个线程池工厂类,该工厂类包含如下集合静态工厂方法来创建线程池:

  • newFixedThreadPool():创建一个任务固定大小、任务队列无界限、可重用的、具有固定线程数的线程池(oom)
  • newSingleThreadExecutor():创建只有一个线程的线程池
  • newCachedThreadPool():创建一个具有缓存功能的线程池
  • newScheduledThreadPool():创建具有指定线程数的线程池,它可以在指定延迟后执行任务线程
  • newWorkStealingPool():创建持有足够线程的线程池来支持给定的并行级别的线程池

(2)ExecutorService接口  Java线程池也采用了面向接口编程的思想,可以看到ThreadPoolExecutorForkJoinPool所有都是ExecutorService接口的实现类,在ExecutorService接口中定义了一些常用的方法,然后再各种线程池中都可以使用ExecutorService接口中定义的方法,常用的方法有如下几个:

向线程池提交线程

  • Future<?> submit():将一个Runnable对象交给指定的线程池,线程池将在有空闲线程时执行Runnable对象代表的任务,该方法既能接收Runnable对象也能接收Callable对象,这就意味着sumbit()方法可以有返回值。
  • void execute(Runnable command):只能接收Runnable对象,意味着该方法没有返回值。

关闭线程池

  • void shutdown():阻止新来的任务提交,对已经提交了的任务不会产生任何影响。(等待所有的线程执行完毕才关闭)
  • List<Runnable> shutdownNow(): 阻止新来的任务提交,同时会中断当前正在运行的线程,另外它还将workQueue中的任务给移除,并将这些任务添加到列表中进行返回。(立马关闭)

检查线程池状态

  • boolean isShutdown():调用shutdown()或shutdownNow()方法后返回为true
  • boolean isTerminated():当调用shutdown()方法后,并且所有提交的任务完成后返回为true;当调用shutdownNow()方法后,成功停止后返回为true。

常见线程池使用示例

(1)newFixedThreadPool    (线程池中的线程数目是固定的,不管来了多少的任务)

package 线程池;

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

/**
 * @author Heian
 * @time 19/03/17 21:11
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:
 */
public class ExecutorSer {

    public static void sleepOneSecond(){
        try {
            TimeUnit.SECONDS.sleep (1);
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }
    public static void sleepFiveSecond(){
        try {
            TimeUnit.SECONDS.sleep (5);
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }
    public static void main(String[] args) {
        //(1)newFixedThreadPool(线程池中的线程数目是固定的,不管来了多少的任务)
        ExecutorService executorService = Executors.newFixedThreadPool (5);
        System.out.println ("FixedThreadPool" + executorService);
        //[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
        for (int i=0;i<6;i++) //定义6个任务
            executorService.execute (() -> {
                ExecutorSer.sleepOneSecond ();
                System.out.println (Thread.currentThread ().getName ());
            });
        System.out.println ("线程正在执行任务的状态:" +executorService);
        //[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0] 如果是三个任务,则pool size=3 说明线程池是懒加载方式创建线程
        executorService.shutdown ();//此方法会让所有线程执行完毕后在关闭,shutdownNow:立马关闭
        System.out.println ("是否执行shutdown方法:"+ executorService.isShutdown () + "执行shutdown方法后状态:"+ executorService) ;
        //true ,[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
        System.out.println ("是否所有线程已经执行完毕:" + executorService.isTerminated ());

        ExecutorSer.sleepFiveSecond ();
        System.out.println ("5s后,是否执行shutdown方法:"+ executorService.isShutdown () + "执行shutdown方法后状态:"+ executorService) ;
        //true  执行shutdown方法后状态:java.util.concurrent.ThreadPoolExecutor@28864e92[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
        System.out.println ("5s后,是否所有线程已经执行完毕:" + executorService.isTerminated ());//true
    }


}

(2)newSingleThreadExecutor(从头到尾整个线程池都只有一个线程在工作)


 ExecutorService executorService1 = Executors.newSingleThreadExecutor ();
        for (int i=0;i<5;i++)
            executorService1.execute (() -> {
                System.out.println (Thread.currentThread ().getName ());
            });       
//可以看到至始至终就只有一个线程在执行任务
/*      pool-2-thread-1
        pool-2-thread-1
        pool-2-thread-1
        pool-2-thread-1
        pool-2-thread-1*/

(3)newCachedThreadPool


   ExecutorService executorService2 = Executors.newCachedThreadPool ();
        System.out.println (executorService2);
        for (int i=0;i<12;i++)
            executorService2.execute (() -> {
                ExecutorSer.sleepOneSecond ();
                System.out.println (executorService2);
            });
   System.out.println ("CacheThreadPool线程提交后,线程状态为" + executorService2);
  /*    java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
        CacheThreadPool线程提交后,线程状态为java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 12, queued tasks = 0, completed tasks = 0]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 8, queued tasks = 0, completed tasks = 4]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 7, queued tasks = 0, completed tasks = 5]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 6, queued tasks = 0, completed tasks = 6]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 5, queued tasks = 0, completed tasks = 7]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 5, queued tasks = 0, completed tasks = 7]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 3, queued tasks = 0, completed tasks = 9]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 2, queued tasks = 0, completed tasks = 10]
        java.util.concurrent.ThreadPoolExecutor@2096442d[Running, pool size = 12, active threads = 1, queued tasks = 0, completed tasks = 11]*/

(4)newScheduledThreadPool (可以在指定延迟后或周期性地执行线程任务的线程池

//建立四个线程  每个500毫秒去打印当前线程的名称
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool (4);
        scheduledExecutorService.scheduleAtFixedRate (() -> {
            System.out.println (Thread.currentThread ().getName ());
        },0,500,TimeUnit.MILLISECONDS);

callable接口的使用

     Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。

  • Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
  • Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
package 线程池.ICallabl;

import java.util.concurrent.*;

/**
 * @author Heian
 * @time 19/03/23 22:27
 * 用途:模拟异步发送接口
 */
public class Icallable {


    //Callable泛型为其异步返回的结果类型  Callable函数式接口
    static class sendEmail implements Callable<String> {
        private long sleepTime;
        public sendEmail(long sleepTime) {
            this.sleepTime = sleepTime;
        }
        @Override
        public String call() throws Exception {
            Thread.sleep (sleepTime);
            System.out.println ("发送emails完毕:"+ Thread.currentThread ().getName ());
            return Thread.currentThread ().getName ();
        }
    }

    static class sendPhoneMsg implements Callable<String> {
        private long sleepTime;
        public sendPhoneMsg(long sleepTime) {
            this.sleepTime = sleepTime;
        }
        @Override
        public String call() throws Exception {
            Thread.sleep (sleepTime);
            System.out.println ("发送短信完毕:"+ Thread.currentThread ().getName ());
            return Thread.currentThread ().getName ();
        }
    }


    public static void main(String[] args) throws Exception{
        long start = System.currentTimeMillis ();
        sendEmail sendEmail = new sendEmail (5000);
        sendPhoneMsg sendPhoneMsg = new sendPhoneMsg (8000);

        FutureTask<String> sendEmailTask = new FutureTask<> (sendEmail);
        FutureTask<String> sendPhonneMsgTask = new FutureTask<> (sendPhoneMsg);

        ExecutorService executorService = Executors.newFixedThreadPool (3);//线程池中的线程数目是固定的,来了多少任务,启动多少线程
        executorService.execute (sendEmailTask);
        executorService.execute (sendPhonneMsgTask);
        while(true){
            if(!sendEmailTask.isDone ()){
                TimeUnit.MILLISECONDS.sleep (500);
                System.out.println ("enlias发送中,请稍后" + Thread.currentThread ().getName ());
            }
            if(!sendPhonneMsgTask.isDone ()){
                TimeUnit.MILLISECONDS.sleep (500);
                System.out.println ("短信发送中,请稍后"+ Thread.currentThread ().getName ());
            }
            if (sendEmailTask.isDone () && sendPhonneMsgTask.isDone ()){
                System.out.println ("两个线程执行完毕");
                executorService.shutdown ();//所有线程执行完毕后再关闭
                return;
            }
            //执行完成
            long end = System.currentTimeMillis ();
            System.out.println ("耗时" +(end-start) + "毫秒");
        }




    /*    while (true){// email:2  短信:5
            if (sendEmailTask.isDone ()){//isDone方法表示任务是否已经完成,若任务完成,则返回true;
                System.out.println ("email执行完毕" + sendEmailTask.get ());//方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
            }
            if (sendEmailTask.isDone () && sendPhonneMsgTask.isDone ()){
                System.out.println ("两个线程执行完毕");  
                executorService.shutdown ();//所有线程执行完毕后再关闭
                return;
            }
        }*/



    }


}

猜你喜欢

转载自blog.csdn.net/qq_40826106/article/details/88628536