线程池

作者: 希希里之海 | 来源:发表于2019-09-15 15:53 被阅读0次

[TOC]

线程池

1. 并发队列:阻塞队列和非阻塞队列

区别如下:

入队:
  • 非阻塞队列:当队列中满了的时候,放入数据,数据丢失
  • 阻塞队列:当队列满了的时候,进行等待,什么时候队列中有出队的数据,那么第 11 个再放进入
出队:
  • 非阻塞队列:如果现在队列中没有元素,取数据,得到的是 null
  • 阻塞队列:等待,什么时候放进去,再取出来

线程池是使用阻塞队列


2. 线程池原理:ThreadPoolExecutor 底层原理解析

2. 1线程的生命周期

从出生到死亡的阶段。

2.2 线程池工作原理
ThreadPoolExecutor t = new ThreadPoolExecutor(1, 3, 0, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(3));

参数含义:

  • 1:核心线程数
  • 3:最大线程数
  • 0 和 TimeUnit.MICROSECONDS:当任务量大于队列长度需要创建线程的时候,新创建的这个线程假如把队列的任务都执行完了,那么等待新任务的空闲时间就是这个
  • new LinkedBlockingDeque<>(3)):阻塞队列:
    • 方法有参数:队列长度为 3
    • 方法无参数:队列长度为 Integer.MAX_VALUE

执行流程图如下所示:

2.3 举个例子
package com.test.jdk8;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPoolExecutor {

    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3));
        // 利用线程池里的线程,开始执行任务
        // 执行第一个任务
        pool.execute(new TestThread());
        // 执行下面三个任务,放入阻塞队列,阻塞队列满:
        pool.execute(new TestThread());
        pool.execute(new TestThread());
        pool.execute(new TestThread());

        // 执行第 4个任务,创建新线程,分摊任务
        pool.execute(new TestThread());

        // 执行第 5 个任务,创建新创建,线程数大于最大线程数,报错
        pool.execute(new TestThread());


        // 关闭线程池
        pool.shutdown();
    }

}

class TestThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

3. 线程池的分类

1. newCachedThreadPool 可缓存线程池

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {
            // lambda 表达式, 实现 new Runnable() 的 run() 方法
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }

}

查看 newCachedThreadPool 源码,可知:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

该线程池的核心线程数为 0, 最大线程数为 Integer.MAX_VALUE,将会根据需要创建新线程,新线程的数量不大于 Integer.MAX_VALUE,线程执行任务结束后被释放可重复使用该线程执行另一个任务。

部分执行结果如下:

pool-1-thread-6
pool-1-thread-11
pool-1-thread-6
pool-1-thread-10
pool-1-thread-4
pool-1-thread-11
pool-1-thread-2
2. newFixedThreadPool 定长线程池

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 100; i++) {
            // lambda 表达式, 实现 new Runnable() 的 run() 方法
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }

}

查看 newFixedThreadPool 源码,可知:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

传入的参数即为核心线程数和最大线程数,核心线程数和最大线程数的数量是相等的。

所以上述示例代码的执行结果的线程数就为 3,部分执行结果如下:

pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
3. newScheduledThreadPool 定时线程池

创建一个定时线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

package ThreadTest;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);

        for (int i = 0; i < 100; i++) {
            ses.schedule(() -> System.out.println(Thread.currentThread().getName()), 3, TimeUnit.SECONDS);
        }

        ses.shutdown();

    }
}

查看 newScheduledThreadPool 源码,如下:

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

可知,newScheduledThreadPool 传入的参数即为核心线程数,最大线程数为 Integer.MAX_VALUE

上述代码通过设置延迟参数 3, 单位 TimeUnit.SECONDS,延迟三秒后执行任务,创建的线程数为 2。执行部分结果如下:

pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
4. newSingleThreadExecutor 单例线程池

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

package ThreadTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String[] args) {
        ExecutorService es = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 100; i++) {
            es.execute(() -> System.out.println(Thread.currentThread().getName()));
        }

        es.shutdown();

    }
}

查看 newSingleThreadExecutor 源码,可知:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

核心线程数和最大线程数都为 1,执行完任务后线程的存活时间为 0,即创建出来的线程只会执行一次任务,保证单例执行。

运行部分结果如下:

pool-1-thread-1
pool-1-thread-1
pool-1-thread-1

相关文章

  • java线程池

    线程VS线程池 普通线程使用 创建线程池 执行任务 执行完毕,释放线程对象 线程池 创建线程池 拿线程池线程去执行...

  • java----线程池

    什么是线程池 为什么要使用线程池 线程池的处理逻辑 如何使用线程池 如何合理配置线程池的大小 结语 什么是线程池 ...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

  • Spring Boot之ThreadPoolTaskExecut

    初始化线程池 corePoolSize 线程池维护线程的最少数量keepAliveSeconds 线程池维护线程...

  • 线程池

    1.线程池简介 1.1 线程池的概念 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性...

  • 多线程juc线程池

    java_basic juc线程池 创建线程池 handler是线程池拒绝策略 排队策略 线程池状态 RUNNIN...

  • ThreadPoolExecutor线程池原理以及源码分析

    线程池流程: 线程池核心类:ThreadPoolExecutor:普通的线程池ScheduledThreadPoo...

  • 线程池

    线程池 [TOC] 线程池概述 什么是线程池 为什么使用线程池 线程池的优势第一:降低资源消耗。通过重复利用已创建...

  • java 线程池使用和详解

    线程池的使用 构造方法 corePoolSize:线程池维护线程的最少数量 maximumPoolSize:线程池...

  • 线程池

    JDK线程池 为什么要用线程池 线程池为什么这么设计 线程池原理 核心线程是否能被回收 如何回收空闲线程 Tomc...

网友评论

      本文标题:线程池

      本文链接:https://www.haomeiwen.com/subject/hnvzyctx.html