线程池原理与使用

java里线程池怎么定义的?什么样的结构?具体使用?

  • 为什么要用线程池,直接一个一个的new线程不行吗?

    1. 主要是线程的资源对于系统来说是占用的资源比较多 比较重量级的一个资源

    2. 这类资源更倾向于个池化的线程池,直接维护好池化的线程池,用的时候从里面取

    3. 如果自己创建线程的话需要维护线程的多少 大小,因为物理资源是有限的

  • 那么线程池是怎么处理大量过来的需要并行计算的业务呢?

    1. 首先要弄一个基础设施业务,线程池是很复杂的,好在jdk已经封装了一些api 包 jdk 已经实现了抽象的线程池的定义

      jdk线程池:

      1.Excutor:执行者顶层接口

      void execute(Runnable command):执行可运行的任务

      2.ExcutorService:接口api

      继承了excutor 接口

      添加了一些其他的方法

      比如: void shutdown() 方法 :停止接受新的任务,原来任务继续执行

      场景:优雅停机维护

      List<Runnable> shutdownNow():停止接受新的任务 ,强制停止之前的任务

      boolean awaitTermination(timeOut, unit):阻塞当前线程,返回是否线程都执行完

      submit()方法

      submit方法->有返回值,用Future封装

      execute 方法->无返回值

      submit 方法还异常可以在主线程中get 捕获到 (注意部分异常 比如算术异常 会被吞掉)

      execute 方法执行任务是捕捉不到异常的

      3.ThreadFactory:线程工厂(设计模式:工厂模式)

      package java0.conc0302.threadpool;
      ​
      import java.util.concurrent.ThreadFactory;
      import java.util.concurrent.atomic.AtomicInteger;
      ​
      /**
       * @author mcc
       * @title: ThreadFactoryDemo
       * @date 2022/5/221:02
       */
      public class ThreadFactoryDemo implements ThreadFactory {
      ​
          private AtomicInteger a=new AtomicInteger(0);
          @Override
          public Thread newThread(Runnable r) {
      ​
              Thread T =new Thread(r);
              //a.getAndIncrement()) 先获取当前值在递增
              T.setName("线程"+a.getAndIncrement());
              return (T);
      ​
          }
      }

      4.ThreadPoolExecutor:调用线程的参数 一般使用这个

      1. 判断corePoolSize(创建)

        判断第一个运行线程数有没有达到 核心线程数 达不到新建一个出来

      2. 加入workQueue

        如果达到!缓存队列排队 !

      3. 判断maximumPoolSize(创建)

        如果缓存队列也满了,判断是否到达最大线程数

      4. 执行拒绝策略处理器

        全满! 拒绝策略处理器

         

      5.Excutors:工具类,创建线程

      缓存队列:

      BlockingQueue是双缓冲队列。BlockingQueue 允许两个线程同时向队列一个存储,一个取出操作。在保证并发安全的同时,提高了队列的存取效率。

      1. ArrayBlockingQueue:规定大小的BlockingQueue,其构造必须指定大小。其所含的对象 是FIFO顺序排序的。

      2. LinkedBlockingQueue:大小不固定的 BlockingQueue,若其构造时指定大小,生成的 BlockingQueue 有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。其所含的对象是 FIFO顺序排序的。

      3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但是其所含对象的排序不是 FIFO, 而是依据对象的自然顺序或者构造函数的 Comparator(比较器 可以根据自己设定好的算法来处理相对应的顺序)决定。

      4.SynchronizedQueue:特殊的 BlockingQueue,对其好澡作必须是放和取交替完成。(只能写入一个值)

      线程池的参数

      拒绝策略

      1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出 RejectedExecutionException异常 默认策略是这个

      2. ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常

      3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝 的任务

      4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务 现在基本上使用这个比较多 因为不会丢任务

        这个的意思是 当前的线程池满了 ,然后还有大量的并发线程的任务 给 主线程,就是调用线程的那个人 ,他自己就会先自己去处理 ;缓解线程池的压力!!

创建线程池的方法:

除了一般使用这个之外ThreadPoolExecutor 。

Excutors工具类为我们提供多个简单的方法:

1. newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因 为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

示例代码:

public class NewSingleThreadExecutorDemo {
​
    public static void main(String[] args) {
​
        ExecutorService executorService = Executors.newSingleThreadExecutor();
​
        for (int i = 0; i < 10; i++) {
            final int no = i;
            executorService.execute(() -> {
                System.out.println("start:" + no);
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("end:" + no);
            });
        }
        executorService.shutdown();
        System.out.println("Main Thread End!");
    }
​
}

start:0 Main Thread End! end:0 start:1 end:1 start:2 end:2 start:3 end:3 start:4 end:4 start:5 end:5 start:6 end:6 start:7 end:7 start:8 end:8 start:9 end:9

2.newFixedThreadPool 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最 大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​
public class NewFixedThreadPoolDemo {
​
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(16);
        for (int i = 0; i < 100; i++) {
            final int no = i;
            executorService.execute(() -> {
                try {
                    System.out.println("start:" + no);
                    Thread.sleep(1000L);
                    System.out.println("end:" + no);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        System.out.println("Main Thread End!");
    }
​
}

类似与jvm xmx xms 一样!

3.newCachedThreadPool

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​
public class NewCachedThreadPoolDemo {
​
    public static void main(String[] args) {
​
        ExecutorService executorService = Executors.newCachedThreadPool();
​
        for (int i = 0; i < 10000; i++) {
            final int no = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("start:" + no);
                        Thread.sleep(1000L);
                        System.out.println("end:" + no);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();
        System.out.println("Main Thread End!");
​
​
    }
​
}

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程, 那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会 对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM))能够创建的最大线程大小。 4..newScheduledThreadPool

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
​
public class NewScheduledThreadExecutorDemo {
​
    public static void main(String[] args) {
​
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(16);
​
        for (int i = 0; i < 100; i++) {
            final int no = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("start:" + no);
                        Thread.sleep(1000L);
                        System.out.println("end:" + no);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            // 10s后执行
            executorService.schedule(runnable, 10, TimeUnit.SECONDS);
        }
        executorService.shutdown();
        System.out.println("Main Thread End!");
​
​
    }
​
}

创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。、

创建固定线程池的经验

不是越大越好,太小肯定也不好:假设核心数为N 1、如果是 CPU 密集型应用,则线程池大小设置为 N或 N+1 2、如果是IO密集型应用,则线程池大小设置为2N 或2N+2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值