线程创建的几种方式和线程池简述

文章目录

  • 前言
  • 一、初始化线程的几种方式?
  • 二、线程池创建的七大参数
    • 1.线程池各参数的含义
    • 2.线程的运行流程
  • 总结


前言

本文是学习线程时的简要记录,仅供参考,如有纰漏,请大家指正。

一、初始化线程的几种方式?

  • 1、继承Thread
  • 2、实现Runnable接口
  • 3、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
  • 4、创建线程池的方式。

方式1和方式2:主线程无法获取线程的运算结果。
方式3:主线程可以获取线程的运算结果,但是不利于控制服务器中的线程资源,可能导致服务器资源耗尽。
方式4:可以通过如下方式初始化线程池。
通过线程池初始化,性能稳定,也可以获取执行结果,并捕获异常。但是在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。

Executors.newFixedThreadPool(10);
//或者
new ThreadPoolExecutor(
              corePoolSize 5,
              maximumPoolSize 200,
              keepAliveTime 10,
              TimeUnit TimeUnit.SECONDS,
              BlockingQueue<Runnable>  new LinkedBlockingQueue<>(10000),
              ThreadFactory Executors.defaultThreadFactory(),
              RejectedExecutionHandler new ThreadPoolExecutor.AbortPolicy()
      );

初始化线程示例代码如下:

public class ThreadTest {

   public static ExecutorService service = Executors.newFixedThreadPool(10);
   public static void main(String[] args) throws ExecutionException, InterruptedException {
       System.out.println("main....start");
       //1、继承Thread
       Thread01 thread01 = new Thread01();
       thread01.start();
     
       //2、实现Runnable接口
       Runnable01 runnable01 = new Runnable01();
       new Thread(runnable01).start();
      
       //3、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
       FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable01());
       new Thread(integerFutureTask).start();
       //等待整个线程执行结束,获取返回结果,阻塞等待
       Integer integer = integerFutureTask.get();
     
       //4、线程池
     
       service.execute(new Runnable01());      
  
       //new ThreadPoolExecutor()
       ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
               5,
               200,
               10,
               TimeUnit.SECONDS,
               new LinkedBlockingQueue<>(10000),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.AbortPolicy()
       );
       System.out.println("main....end");
   }

   //1、继承Thread
   public static class Thread01 extends Thread{
       @Override
       public void run() {
           System.out.println("当前线程:"+Thread.currentThread().getId());
           int i=10/2;
           System.out.println("运行结果:"+i);
       }
   }
   public static class Runnable01 implements Runnable{
       @Override
       public void run() {
           System.out.println("当前线程:"+Thread.currentThread().getId());
           int i=10/2;
           System.out.println("运行结果:"+i);
       }

   }
   public static class Callable01 implements Callable<Integer>{

       @Override
       public Integer call() throws Exception {
           System.out.println("当前线程:"+Thread.currentThread().getId());
           int i=10/2;
           System.out.println("运行结果:"+i);
           return i;
       }
   }

}

二、线程池创建的七大参数

1.线程池各参数的含义

线程创建的几种方式和线程池简述_第1张图片

  • int corePoolSize:[5]核心线程数【5个一直存在除非设置了allowCoreThreadTimeOut】,线程池创建好以后就准备就绪的线程数量,就等待来接收异步任务去执行。

  • int maximumPoolSize:最大线程数量;控制资源并发的。

  • long keepAliveTime:存活时间,如果当前数量大于核心线程数量。线程空闲的时间大于存活时间,释放除核心线程外的超存活时间的空闲线程。

  • TimeUnit unit:时间单位。

  • BlockingQueue workQueue:阻塞队列,如果任务有很多,就会将目前多的任务放在队列里面。只要有空闲的线程,就会去队列中取出新的任务继续执行。

  • ThreadFactory threadFactory:线程的创建工厂,也可以自定义。

  • RejectedExecutionHandler handler:如果队列满了按照我们指定的拒绝策略拒绝执行任务。

2.线程的运行流程

1、线程池创建好,准备好core数量的核心线程,准备接收任务

  • 1.1、core满了,就将再进来的任务放进阻塞队列中,空闲的core就会自己去阻塞队列获取任务执行
  • 1.2、阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
  • 1.3、max满了就用RejectedExecutionHandler拒绝任务
  • 1.4、max都执行完了,在指定的时间keepAliveTime以后,释放,max-core数量的线程

2、线程池运行例题
假如一个线程池,corePoolSize:7,maximumPoolSize:20,workQueue:50,有100个线程同时进来,怎么分配?

先用7个直接可以得到执行,接下来50个进入阻塞队列排队,再多开13个线程继续执行。现在70个线程已经分配,剩下30个线程使用设置好的拒绝策略。

总结

本文为学习中的笔记,以后会继续完善。

你可能感兴趣的:(java基础知识,java)