欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java中基本线程池介绍

程序员文章站 2022-06-01 13:29:35
...


前言

本文章只针对Exectors去创建线程池,让大家对线程池先有点基本的了解,但是实际开发中不允许用这样的方式去创建,而是通过ThreadPoolExecutor方式(最原始的线程池创建方式,之后的文章会涉及)。

一、newFixedThreadPool

  • 定义:创建一个线程池,重用固定数量的线程,从共享*队列中运行,使用提供的ThreadFactory在需要时创建新线程。 在任何时候,最多nThreads个线程将处于主动处理任务。 如果所有线程处于活动状态时,提交其他任务,则它们将在等待队列中直到线程可用。 如果任何线程由于在关闭之前的执行期间发生故障而终止,则如果需要执行后续任务,则新线程将占用它。 池中的线程将存在,直到它明确地被shutdown 。
  • 使用场景:适用于任务量已知,相对耗时的任务。
  • 举例加分析(代码中)
public class testCreateThreadPool {
    public static void main(String[] args)  {
        //创建固定大小为3的线程
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i <5 ; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行");
                }
            });
        }
        //shutdown三个线程,结束
        executorService.shutdown();
        /*
        运行结果:
        pool-1-thread-2执行
        pool-1-thread-3执行
        pool-1-thread-2执行
        pool-1-thread-3执行
        pool-1-thread-1执行
         */
        /*
        分析:一共只有三个线程,因此这5个任务是由这三个线程完成的
         */
    }
}

二、newCachedThreadPool

  • 定义:一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源
  • 使用场景:适合任务数比较密集,但每个任务执行时间较短的情况。
  • 举例加分析(代码中)
public class testCreateThreadPool {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i <5 ; i++) {
            //Thread.sleep(100);//注释掉是运行结果1,不注释掉是运行结果2
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行");
                }
            });
        }

        /*
        运行结果1:
        pool-1-thread-4执行
        pool-1-thread-3执行
        pool-1-thread-2执行
        pool-1-thread-5执行
        pool-1-thread-1执行
        运行结果2:
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
         */
        /*
        分析:
        运行结果1一共创建了5个线程,这是因为5个任务之间的间隔很短,
        第二个任务要执行时,第一个任务未完成(该任务创建的线程当前不可用)
        因此只能在创建第二个,以此类推
        运行结果2一共创建了1个线程,这是因为每个任务之间间隔了200ms,
        这个时间足够创建的线程完成任务,在下一个任务到来前处于可用状态
         */
    }
}

三、newSingleThreadExector

  • 定义:创建一个使用从*队列运行的单个工作线程的执行程序。(注意:如果这个单个线程由于在关闭之前的执行过程中发生故障而终止,则如果需要执行后续任务,则新的线程将占用它。)任务保证顺序执行,并且不超过一个任务将被**在任何给定的时间。
  • 使用场景:希望多个任务排队执行。因为线程数固定为1,任务数多于1时,会放入*队列排队。任务执行完毕后,这唯一的线程也不会被释放。
  • 举例加分析(代码中)
public class testCreateThreadPool {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i <5 ; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行");
                }
            });
        }
executorService.shutdown();
        /*
        运行结果:
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
        pool-1-thread-1执行
         */
        /*
        分析:
        因为该线程是单线程执行器,因此只有一个线程执行所有任务
         */
    }
}

四、newScheduledThreadPool

  • 定义:创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行
  • 使用场景:任务需要周期性或者定时执行。
  • 举例加分析(代码中)
public class testCreateThreadPool {
    //线程安全的队列
    static Queue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
    static {
        for (int i = 1; i <=5 ; i++) {
            queue.add(i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        //获取时间
        SimpleDateFormat sdf=new SimpleDateFormat("hh:mm:ss");
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        for (int i = 0; i <5 ; i++) {
            int curVal=queue.poll();
          scheduledExecutorService.schedule(new Runnable() {
              @Override
              public void run() {
                  System.out.println("在"+sdf.format(new Date())+"时,线程执行了第"+curVal+"个任务");
              }
          },curVal,TimeUnit.SECONDS);

        }
        scheduledExecutorService.shutdown();

        /*
        运行结果:
        在09:31:28时,线程执行了第1个任务
        在09:31:29时,线程执行了第2个任务
        在09:31:30时,线程执行了第3个任务
        在09:31:31时,线程执行了第4个任务
        在09:31:32时,线程执行了第5个任务
         */
        /*
        分析:
          public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
          本例中delay为1,2,3,4,5,unit为秒,即5个任务分别延迟1,2,3,4,5秒后执行
         */
    }