자바 멀티 스레드 노트 (4) 스레드 풀

머리말

단지 연구 노트로, 학습 과정을 녹화
이미 스레드 잠금 장치 배운
스레드 풀, 키 어려운 - 다음 스레드의 관리 배울
과정의 공개 Java3y 번호
자바 주에서 동시 프로그래밍 - (F) JUC 스레드 풀 -02ThreadPoolExecutor 구현 원리

디렉토리

  1. 개념
  2. 호출 가능 和 미래
  3. 자세한 ThreadPoolExecutor입니다
    3.1. 속성
    3.2. 큐 정책
    3.3. 생성자
    3.4 의 속성을 요약
  4. 스레드 풀 상태
  5. 사명
  6. 스레드 풀을 닫습니다

스레드 풀

개념

자세한 갱스터 : 자바 동시주의 프로그래밍 - (F) JUC 스레드 풀 -01 개요

유휴 스레드를 요청하기 위해 스레드 풀 작업은 (오히려 파괴보다) 다음 작업을 기다리고 스레드 풀에 다시 완료 : 요청이 들어 오면 어떤 작업 스레드가 대기하지있을 때 스레드 풀 스레드의 모음입니다. 이 실현 재사용 스레드 , 성능을 크게 향상시킬 수 있습니다

사용 공통점이 직접 작성하고 파괴

 CreatThread1 thread1=new CreatThread1();
 Thread myThread1=new Thread(thread1);
 myThread1.start();

각 요청에 대한 스레드를 생성하는 것은 특정 단점이 있습니다 :

  • 스레드 수명주기 비용이 매우 높다. 각 스레드는 시간과 자원을 작성하고 더 많은 고객에 소요되는 처리 시간과 자원을보다 작업 thread를 파괴하는 동안, 자신의 라이프 사이클을 가지고 있으며, 자원을 소모하는 몇 가지 유휴 스레드가있을 것입니다.

  • 프로그램의 안정성과 견고성은 스레드를 열고 각 요청을 떨어질 것이다. 악의적 인 공격이나 (메모리 부족) 과도의 요청은,이 프로그램에 쉽게 경우 붕괴를 다했다.

스레드 풀 스레드를 줄이기 위해 생성 된 스레드의 반복 사용으로 인한 파괴를 생성하고 소비 할 수

스레드 풀 jdk1.8
그림 삽입 설명 여기

집행자

executor 스레드 풀은 상기 인터페이스의 상단 인 스레드 풀의 기초
(디커플링) 및 "명령"이 분리는 "미션 제출"메커니즘을 제공 실행자

그림 삽입 설명 여기
이러한 방법 실행 (Runnable를) 제출 실행의 Runnable 작업

그리고 클래스 집행 인 하나 이상의 아이

ExecutorService를

ExecutorService를은 처리 작업이 주어진 작업을 수행하기 위해 기다리고 정지 해, 실행 중의 액티브 한 태스크 모든 정지 시도, 실행의 Runnable 태스크를 제출의 Executor 인터페이스를 상속
그림 삽입 설명 여기
수명주기 관리 방법을 제공 ExecutorService를 스레드 풀을
그림 삽입 설명 여기

AbstractExecutorService

추상 클래스, 상속 ExecutorService를 인터페이스, 구현 클래스 ExecutorService입니다입니다
그림 삽입 설명 여기

ScheduledExecutorService를 和로 스케줄

ScheduledExecutorService를는 ExecutorService를이 소정으로 배치 될 수 유전 조작 또는 주기적으로 실행하기 위해 지연된
로 스케줄이있는 ThreadPoolExecutor 실현 ScheduledExecutorService를 상속

그림 삽입 설명 여기

ThreadPoolExecutor입니다

확장 가능한 스레드 풀 구현, 일반적인 스레드 풀을 제공합니다
더에 대해 배울 필요를

ForkJoinPool

JDK1.7中新增的一个线程池,与ThreadPoolExecutor一样,同样继承了AbstractExecutorService。ForkJoinPool是Fork/Join框架的两大核心类之一。与其它类型的ExecutorService相比,其主要的不同在于采用了工作窃取算法(work-stealing):所有池中线程会尝试找到并执行已被提交到池中的或由其他线程创建的任务。这样很少有线程会处于空闲状态,非常高效。这使得能够有效地处理以下情景:大多数由任务产生大量子任务的情况;从外部客户端大量提交小任务到池中的情况

CompeleteFuture、并发流等都是基于ForkJoinPool实现
ForkJoinPool

Callable和Future

前面创建线程时使用的是Runnable接口,它是无返回值的,还有有返回值的创建线程的方法,就是继承Callable接口

Callable接口与Runnable接口类似

그림 삽입 설명 여기
Future是一个未来对象,保存线程结果
그림 삽입 설명 여기
执行Callable方式,需要Future的实现类的支持,用于接收运算结果。FutureTask是Future接口的实现类

package com.company.Thread.Callable;

import java.util.concurrent.*;

public class MyCallable implements Callable<Integer> {
    private int count=3;
    public  MyCallable(int count){
        this.count=count;
    }

    @Override
    public Integer call() throws Exception {
        return count;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //创建线程固定的线程池
        ExecutorService pool= Executors.newFixedThreadPool(2);

        //future接收返回值
        Future future=pool.submit(new MyCallable(100));
        Future future1=pool.submit(new MyCallable(200));

        System.out.println(future.get());
        System.out.println(future1.get());
        //线程池关闭
        pool.shutdown();
    }  
}

그림 삽입 설명 여기

ThreadPoolExecutor详解

属性

Java中常用的线程池有三个,最出名的当然是ThreadPoolExecutor,除此之外还有ScheduledThreadPoolExecutor、ForkJoinPool
그림 삽입 설명 여기
推荐使用Executor工厂方法配置,有3种常见的使用场景的配置
Executors.newCachedThreadPool()(自动线填海无界线程池)
Executors.newFixedThreadPool(int)(固定大小的线程池)
Executors.newSingleThreadExecutor()(单个后台线程)

当然也可以手动配置
手动配置需要了解属性:
그림 삽입 설명 여기그림 삽입 설명 여기
这个大佬的详解更清晰(Java3y公众号:线程池

그림 삽입 설명 여기
通过这些自定义属性,可以解析3个常用线程池配置,它们都在Executors类下

그림 삽입 설명 여기

  • newCachedThreadPool
    그림 삽입 설명 여기它设置了5个参数:
    核心池大小:无界值Integer.MAX_VALUE
    线程池中线程空闲时的活动时间:以秒为单元粒度的时间段
    SynchronousQueue 排队策略

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
调用 execute 将重用以前构造的线程(如果线程可用)。
如果现有线程没有可用的,则创建一个新线程并添加到池中。
终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
因此,长时间保持空闲的线程池不会使用任何资源

  • newFixedThreadPool
    그림 삽입 설명 여기5个参数:
    根据传入的nThreads定义corePoolSize和maximumPoolSize,即相等
    线程池中线程空闲时的活动时间:以毫秒为单元粒度
    LinkedBlockingQueue 排队策略

一个固定线程数的线程池,它将返回一个corePoolSize和maximumPoolSize相等的线程池

  • newSingleThreadExecutor
    그림 삽입 설명 여기5个参数:
    corePoolSize和maximumPoolSize相同为1,即固定单线程
    以毫秒为线程空闲活动时间
    LinkedBlockingQueue 排队策略

使用单个worker线程的Executor

排队策略

SynchronousQueue :
它将任务直接传输给工作队列workers,而不保持任务。如果不存在空闲线程,则会新建一个线程来执行任务
그림 삽입 설명 여기

LinkedBlockingQueue
无界队列,使用此队列会导致在所有corePoolSize线程都忙时新任务在队列中等待。这样,创建的线程就不会超过最大值(maximumPoolSize无意义)

그림 삽입 설명 여기ArrayBlockingQueue:
有界队列,少用

ThreadPoolExecutor构造方法

可以选择自定义ThreadPoolExecutor,它有4个构造方法
大致就是设置前面学到的各个属性
그림 삽입 설명 여기
最复杂的一个:
그림 삽입 설명 여기

  • 指定核心池线程数量corePoolSize
  • 指定最大池线程数量maximumPoolSize
  • 池中线程空闲时的活动时间keepAliveTime
  • 单元粒度的时间段TimeUnit
  • 阻塞队列BlockingQueue< Runnable>
  • 线程工厂ThreadFactory
  • 任务拒绝策略RejectedExecutionHandler

总结属性

线程数量corePoolSize、maximumPoolSize要点:

  • 如果运行线程的数量少于核心线程数量,则创建新的线程处理请求
  • 如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程
  • 如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池
  • 如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量

池中线程空闲时的活动时间maximumPoolSize:

  • 当前线程数大于核心线程数,如果空闲时间已经超过了,那该线程会销毁

排队策略要点:

  • 同步移交:不会放到队列中,而是等待线程执行它。如果当前线程没有执行,很可能会新开一个线程执行。(SynchronousQueue )
  • 无界限策略:如果核心线程都在工作,该线程会放到队列中。所以线程数不会超过核心线程数(LinkedBlockingQueue:不具有预定义容量)
  • 有界限策略:防止资源耗尽,当最大线程数有限时,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷(ArrayBlockingQueue)

当 Executor 已经关闭,并且 Executor 将有限边界用于最大线程和工作队列容量,且已经饱和时,在方法 execute(java.lang.Runnable) 中提交的新任务将被拒绝

拒绝任务策略:

  • ThreadPoolExecutor.AbortPolicy ,默认策略,处理程序遭到拒绝将抛出运行时
    RejectedExecutionException。
  • ThreadPoolExecutor.CallerRunsPolicy,线程调用运行该任务的 execute
    本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
  • ThreadPoolExecutor.DiscardPolicy,不能执行的任务将被删除。
  • ThreadPoolExecutor.DiscardOldestPolicy,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

线程池状态

그림 삽입 설명 여기그림 삽입 설명 여기
线程池的5种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED

ctl对象一共32位,高3位保存线程池状态信息,后29位保存线程池容量信息。线程池的初始化状态是RUNNING
그림 삽입 설명 여기

执行任务

package com.company.Thread.Callable;

import java.util.concurrent.*;

public class MyCallable implements Callable<Integer> {
    private int count=3;
    public  MyCallable(int count){
        this.count=count;
    }

    @Override
    public Integer call() throws Exception {
        return count;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //创建线程固定的线程池
        ExecutorService pool= Executors.newFixedThreadPool(2);

        //future
        Future future=pool.submit(new MyCallable(100));
        Future future1=pool.submit(new MyCallable(200));

        System.out.println(future.get());
        System.out.println(future1.get());
        //线程池关闭
        pool.shutdown();
    }
}

这个程序中启动线程池submit方法

/**
  * 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
  * 该 Future 的 get 方法在 成功 完成时将会返回 null。
  */
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

submit又是调用execute方法

그림 삽입 설명 여기execute()分三种情况处理任务

case1:如果线程池中运行的线程数量<corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。
case2:如果线程池中运行的线程数量>=corePoolSize,且线程池处于RUNNING状态,且把提交的任务成功放入阻塞队列中,就再次检查线程池的状态,1.如果线程池不是RUNNING状态,且成功从阻塞队列中删除任务,则该任务由当前 RejectedExecutionHandler 处理。2.否则如果线程池中运行的线程数量为0,则通过addWorker(null, false)尝试新建一个线程,新建线程对应的任务为null。
case3:如果以上两种case不成立,即没能将任务成功放入阻塞队列中,且addWoker新建线程失败,则该任务由当前 RejectedExecutionHandler 处理

这就是Executor工厂方法配置线程池

关闭线程池

shutdown()方法和shutdownNow()方法
그림 삽입 설명 여기그림 삽입 설명 여기shutdown() 按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务
shutdownNow()尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表

shutdown和shutdownNow详解

shutdown()和shutdownNow()的区别

  • 调用shutdown()后,线程池状态立刻变为SHUTDOWN,而调用shutdownNow(),线程池状态立刻变为STOP
  • shutdown()通过中断空闲线程、不接受新任务的方式按过去执行已提交任务的顺序发起一个有序的关闭,shutdownNow()无差别地停止所有的活动执行任务,暂停等待任务的处理。也就是说,shutdown()等待任务执行完才中断线程,而shutdownNow()不等任务执行完就中断了线程。
게시 49 개 원래 기사 · 원의 칭찬 0 · 조회수 1218

추천

출처blog.csdn.net/key_768/article/details/104324066