线程池+ Callable +CompletableFuture 的基本使用

线程池的作用

    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
 */
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;
            }
        }*/



    }


}

Callable  拓展

package 线程池.ICallabl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 模拟业务场景:处理耗时任务,它会以最长的业务时间返回,不是响应式
 */

public class InvokeAllTest {

    //任务一
    public String do3Second() {
        try {
            System.out.println ("正在执行3秒的方法");
            TimeUnit.SECONDS.sleep (3);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##3";
    }
    //任务二
    public String do5Second() {
        try {
            System.out.println ("正在执行5秒的方法");
            TimeUnit.SECONDS.sleep (5);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##5";
    }

    public static void main(String[] args) throws Exception{
        long start = System.currentTimeMillis ();
        InvokeAllTest demo = new InvokeAllTest ();
        ExecutorService executorService = Executors.newFixedThreadPool (20);
        List<Callable<String>> callList = new ArrayList<> ();
        for (int value = 0; value < 5; value++) {
            callList.add (() -> demo.do3Second ());
            callList.add (() -> demo.do5Second ());
        }
        //把所有的任务放入到线程池里
        List<Future<String>> futures =  executorService.invokeAll (callList);
        futures.forEach (strFture ->{
            while (true){
                //只有当所有任务执行了,返回结果集
                if (strFture.isDone ()){
                    String s = null;
                    try {
                        s = strFture.get ();
                        System.out.println (s + "耗时:" + (System.currentTimeMillis () - start));
                        break;
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace ();
                    }
                }
            }
        });
        System.out.println ("阻塞此处 执行完毕");
        executorService.shutdown ();
    }

}
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行5秒的方法
正在执行3秒的方法
pool-1-thread-1##3耗时:5078
pool-1-thread-2##5耗时:5078
pool-1-thread-3##3耗时:5078
pool-1-thread-4##5耗时:5078
pool-1-thread-5##3耗时:5078
pool-1-thread-6##5耗时:5078
pool-1-thread-7##3耗时:5078
pool-1-thread-8##5耗时:5078
pool-1-thread-9##3耗时:5078
pool-1-thread-10##5耗时:5078
阻塞此处 执行完毕

将任务加入到集合并发的执行,因为必须等到每一个线程执行成功后方能退出循环,所以打印时间都是以最长的时间为准的,并不能做到响应式编程,优化后代码如下:

package 线程池.ICallabl.异步非阻塞;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

/**
 * 模拟业务场景:处理耗时任务,处理完一个任务返回一个任务结果,响应式
 */
public class ComletableTest {

    //任务一
    public String do3Second() {
        try {
            System.out.println ("正在执行3秒的方法");
            TimeUnit.SECONDS.sleep (3);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##3";
    }
    //任务二
    public String do5Second() {
        try {
            System.out.println ("正在执行5秒的方法");
            TimeUnit.SECONDS.sleep (5);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##5";
    }


    public static void main(String[] args) {
        long start = System.currentTimeMillis ();
        ComletableTest demo = new ComletableTest ();
        AtomicInteger num = new AtomicInteger ();
        ExecutorService executorService = Executors.newFixedThreadPool (20);
        IntStream.range (0,5).forEach (value -> {
            CompletableFuture.supplyAsync (() -> {
                return demo.do3Second ();
            },executorService).whenComplete ((resultStr, throwable) -> {
                num.addAndGet (1);
                System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
            });
            CompletableFuture.supplyAsync (() -> {
                return demo.do5Second ();
            },executorService).whenComplete ((resultStr, throwable) -> {
                num.addAndGet (1);
                System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
            });
        });

        System.out.println ("非阻塞 执行完毕");
        while (true){
            if (num.get () == 10){
                System.out.println ("任务执行完毕!");
                executorService.shutdown ();
                break;
            }

        }
    }




}
正在执行3秒的方法
正在执行5秒的方法
正在执行5秒的方法
正在执行3秒的方法
非阻塞 执行完毕
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
正在执行3秒的方法
正在执行5秒的方法
pool-1-thread-1##3耗时:3075
pool-1-thread-5##3耗时:3078
pool-1-thread-3##3耗时:3078
pool-1-thread-7##3耗时:3079
pool-1-thread-9##3耗时:3079
pool-1-thread-4##5耗时:5079
pool-1-thread-6##5耗时:5079
pool-1-thread-2##5耗时:5079
pool-1-thread-8##5耗时:5080
pool-1-thread-10##5耗时:5083
任务执行完毕!

需要注意一点的就是: supplyAsync、whenComplete使用的都是deamon线程,主线程退出,会导致任务异常关闭

package 线程池.ICallabl.异步非阻塞;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 *whenComplete  完成时 触发的事件  supplyAsync、whenComplete使用的都是deamon线程,主线程退出后,进程退出,导致结果没有打印
 */
public class ComletableDemo {

    //任务一
    public String do3Second() {
        try {
            System.out.println ("正在执行3秒的方法");
            TimeUnit.SECONDS.sleep (3);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##3";
    }
    //任务二
    public String do5Second() {
        try {
            System.out.println ("正在执行5秒的方法");
            TimeUnit.SECONDS.sleep (5);
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return Thread.currentThread ().getName () + "##5";
    }


    public static void main(String[] args) throws Exception{
        long start = System.currentTimeMillis ();
        ComletableDemo demo = new ComletableDemo ();
        IntStream.range (0,5).forEach (value -> {
            CompletableFuture.supplyAsync (() -> {
                return demo.do3Second ();
            }).whenComplete ((resultStr, throwable) -> {
                System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
            });
            CompletableFuture.supplyAsync (() -> {
                return demo.do5Second ();
            }).whenComplete ((resultStr, throwable) -> {
                System.out.println (resultStr + "耗时:" + (System.currentTimeMillis () - start));
            });
        });

        System.out.println ("我没有被阻塞住");
        Runtime.getRuntime ().addShutdownHook (new Thread (() -> {
            System.out.println ("任务执行完成,JVM退出程序");
        }));
       // Thread.sleep (1000000L);
    }
    //supplyAsync  默认使用的是守护线程,所以当执行到main线程后,已经没有非守护线程了,此时任务还没执行完成,所以要指定线程池



}
正在执行3秒的方法
正在执行5秒的方法
我没有被阻塞住
正在执行3秒的方法
任务执行完成,JVM退出程序

自定义单例线程池和自定义线程名称

        在任务不多的情况下,其实一个项目是可以公用一个线程池,那么我们就联想到了单例模式,那我们可以用7种单利模式中的holder模式去涉及,而且为了便于区分每个线程的名称(一般线程池线程名称为pool-1-thread-2  其组成为:线程组名+线程名),而且一般要实现线程自定义命名必须要实现ThreadFactory接口,具体实现方法,可以参见Executors这个类,这个类有个内部类实现了ThreadFactory接口,源码如下:

  /**
     * The default thread factory
     */
    static class DefaultThreadFactory implements ThreadFactory {
 
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;//线程名后缀

        MyThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
            //如果这个内部类是外部类,那么每调用一次poolNumber就会+1,目前内部类实际上就固定不变了1
        }

        //线程工厂 制造线程
        public Thread newThread(Runnable r) {
            //线程构造方法
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            //将守护线程设置为非守护线程
            if (t.isDaemon())
                t.setDaemon(false);
            //统一将线程优先级设置为5  默认是5 Thread.NORM_PRIORITY
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
package 线程池.自定义线程池线程名称;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author heian
 * @create 2020-01-08-1:55 下午
 * @description 单例自定义线程池
 */
public final class SingleThreadPool {

    private ExecutorService executors = new ThreadPoolExecutor
            (5,10,3, TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),new SingleThreadPool.MyThreadFactory());


    private SingleThreadPool(){
    }
    //静态内部类
    private static class Holder{
        private static SingleThreadPool singleThreadPool = new SingleThreadPool();
    }

    //静态内部类
    private static class MyThreadFactory implements ThreadFactory {

        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;//线程名后缀

        MyThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = "myPool-" + poolNumber.getAndIncrement() + "-myThread-";
            //如果这个内部类是外部类,那么每调用一次poolNumber就会+1,目前内部类实际上就固定不变了1
        }

        //线程工厂 制造线程
        public Thread newThread(Runnable r) {
            //线程构造方法
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            //将守护线程设置为非守护线程
            if (t.isDaemon())
                t.setDaemon(false);
            //统一将线程优先级设置为5  默认是5 Thread.NORM_PRIORITY
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }


    //返回所需单例类
    public static SingleThreadPool  getInstance(){
        return Holder.singleThreadPool;
    }

    //返回单例类所需变量
    public ExecutorService getExecutors() {
        return executors;
    }

}

 通过测试类测试

package 线程池.自定义线程池线程名称;

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

/**
 * @author heian
 * @create 2020-01-08-2:18 下午
 * @description 测试类
 */
public class TestSingle {

    public static void task() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ExecutorService executors = SingleThreadPool.getInstance().getExecutors();
        for (int i = 0; i <10 ; i++) {
            executors.submit(() -> {
                try {
                    task();
                    System.out.println(executors.toString());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

    }
}
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=55035:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/tools.jar:/Users/humingming/Downloads/firstPro/out/production/firstPro 线程池.自定义线程池线程名称.TestSingle
myPool-1-myThread-3
myPool-1-myThread-1
myPool-1-myThread-5
myPool-1-myThread-2
myPool-1-myThread-4
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]
myPool-1-myThread-3
myPool-1-myThread-5
myPool-1-myThread-2
myPool-1-myThread-1
myPool-1-myThread-4
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]
java.util.concurrent.ThreadPoolExecutor@376feed8[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]

        可以看见 线程池名字改了,如果是多个线程池不公用则需要将实现MyThreadFactory类抽成一个单独的类,并且可以发现当任务为10线程只启动了5个,另外5个任务会进入队列。所以又有以下规则:

  1. 池中的线程 > corePoolSize  的线程,多出的线程在空闲时间keepAliveTime 时将会终止
  2. 运行的线程 < corePoolSize  的线程,则线程池继续添加新的线程,而不进行排队
  3. 运行的线程 >= corePoolSize  的线程,则线程池添加到队列,而不是增加线程
  4. maxPoolSize >  运行的线程 >corePoolSize,当且仅当线程池队列满,才会创建新的线程
  5. 池中的线程>maxPoolSize ,这种情况下会采取拒绝策略 (抛出RejectedExecutionException)
核心线程数10,最大线程数30,keepAliveTime是3秒

随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,

这时多余的任务通过加入阻塞队列来运行,

当超出阻塞队列长度+核心线程数时,

这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30

那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值