Java中线程池实现的两种方式

作者: PageThinker | 来源:发表于2020-04-16 18:19 被阅读0次
01.png

01 线程池的应用场景

(1)应用

比如现在收集上的修图软件。一张 1920 x1080 的图片有 200多万个像素点,对整个图片的每个像素点处理一遍也是需要不少的计算量。

(2)服务器端

服务器端处理大数据、大量请求时如果只是单个线程来进行,也是无法满足需求的。

此外,不管是处理应用还是服务器,即使使用了多线程,如果频繁进行创建和销毁线程,最终创建和销毁的时间有可能大于真正执行的时间。将对象复用是一个不错的选择,因此可以选择线程池。

线程池涉及到的常用的 Java 类包括 ThreadPoolExecutor、Executors 等。

02 ThreadPoolExecutor

(1)ThreadPoolExecutor 创建对象较为复杂,如下图是在 JDK 11 中提供的几个构造函数。

02.png

这些参数主要涉及到线程池一些关键参数的设置。以参数最多的这个构造函数为例:

public ThreadPoolExecutor(int corePoolSize, 
                                                    int maximumPoolSize, 
                                                    long keepAliveTime, 
                                                    TimeUnit unit, 
                                                    BlockingQueue<Runnable> workQueue, 
                                                    ThreadFactory threadFactory, 
                                                    RejectedExecutionHandler handler) {
    ...
}

corePoolSize 空闲时线程池中保存的线程数。

maximumPoolSize 线程池中允许的最大线程数。

keepAliveTime 当有空闲线程时,且现有的线程数大于 corePoolSize 在超过该指定的时间则删除该线程,在指定的时间内并不删除线程。

unit 指设置的 keepAliveTime 的时间单位。

workQueue 执行前用来保存任务队列。

threadFactory 指定创建自定义线程的工厂类。

handler RejectedExecutionHandler 的作用是当线程池关闭之后如有任务加入的时候,可以实现一些处理,例如将被拒绝的线程信息记录下来。

(2)execute() 和 submit() 方法

两者都是能像线程池提交任务的,但是细节会有不同。

execute() 可以添加一个任务,但是类型只能是Runnable 类型,且该任务不能返回结果。当遇到自线程异常时,直接打印异常信息,主线程无法捕获异常信息。

submit() 可以添加一个任务,但是返回一个 Future 对象,并能够通过 Future 获得返回结果。当遇到异常时,能够在主线程中捕获异常信息。

submit() 方法的参数涉及到两类 callable 接口和 Runnable ,它们的主要区别是:

(a)Callable 接口的 call() 方法可有返回值,而 Runnable 接口的 run() 方法没有返回值。

(b)Callable 接口的 call() 方法可以生命抛出异常,而 Runnable 接口的 run() 方法不可以声明抛出异常。

(3)其他常用方法

shutdown() 主线程立即结束,且不会阻塞,线程池中为执行完的线程会继续执行,线程池中不在添加新的 Task,线程池会继续运行知道线程都执行完成。

当线程会立即编程 SHUTDOWN 状态,此时不再想线程池中添加 Task,否则抛出 RejectedExecutionException 异常。

shutdownNow()中断所有的任务,并抛出 InterruptException 异常。执行后立即进入 STOP 状态,并试图停止所有正在执行的线程,不再处理还在线程池中等待的任务。

该方法执行后会返回未执行的任务:List<Runnable>

isShutdown() 判断线程池是否已经关闭。

isTerminating() 是否正在终止的过程中时,返回 true。

isTerminated() 判断所有任务都已经完成。

awaitTermination() 查看在指定的时间之间,线程池是否已经终止工作。

03 Executors

Executors 是线程池的创建类,能够方便通过已经提供的方法的创建线程池。

(1)Executors 提供的常用方法:

newCachedThreadPool() 创建无边界的线程池,可以进行线程自动回收,所谓“最大线程池”就是池中存放线程数位理论上的最大值, Integer.MAX_VALUE 最大值。

newCachedThreadPool(ThreadFactory) 自定义线程池中的线程

newFixedThreadPool(int) 创建有边界的线程池

newFixedThreadPool(int, ThreadFactory) 创建自定义线程的有边界线程池。

newSingleThreadExector() 创建单一线程池,可实现以队列的方式执行任务。

newSingleThreadExecutor() 用工厂方式创建单一线程池。

04 案例

(1)使用 ThreadPoolExecutor 创建线程池

package com.page.concurrent.pool;

import java.util.concurrent.*;

public class Game {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                1, 2, 1000 * 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        Future<String> future = threadPoolExecutor.submit(() -> {
            System.out.println("Should work 4 seconds.");
            Thread.sleep(1000 * 4);
            System.out.println("Work done.");
            return "OK";
        });

        String result = future.get();
        System.out.println("Thread response result is " + result);
        threadPoolExecutor.shutdownNow();
        System.out.println("Thread pool status: isShutdown=" + threadPoolExecutor.isShutdown());
        Thread.sleep(1000 * 5);
        System.out.println("Thread pool status: isTerminated" + threadPoolExecutor.isTerminated());
    }
}

(2)使用 Executors 创建线程池

package com.page.concurrent.pool;

import java.util.concurrent.*;

public class Game {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<String> future = executorService.submit(() -> {
            System.out.println("Should work 4 seconds.");
            Thread.sleep(1000 * 4);
            System.out.println("Work done.");
            return "OK";
        });

        String result = future.get();
        System.out.println("Thread response result is " + result);
        executorService.shutdownNow();
        System.out.println("Thread pool status: isShutdown=" + executorService.isShutdown());
        Thread.sleep(1000 * 5);
        System.out.println("Thread pool status: isTerminated" + executorService.isTerminated());
    }
}

相关文章

  • 线程池的基本用法

    1.为什么要用线程池在java中,开启线程的方式一般分为两种:a.继承Thread,实现其run方法b.实现Run...

  • [第三期:JAVA并发:线程池管理 ThreadPoolExec

    源码不会骗你的!!! 一、背景 JAVA通过多线程的方式实现并发,为了方便线程池的管理,JAVA采用线程池的方式对...

  • 线程池任务执行过程

    前言 JAVA通过多线程的方式实现并发,为了方便线程池的管理,JAVA采用线程池的方式对线线程的整个生命周期进行管...

  • 线程池底层原理

    概述 JAVA通过多线程的方式实现并发,为了方便线程池的管理,JAVA采用线程池的方式对线线程的整个生命周期进行管...

  • java多线程-线程池

    java中不可避免的就是使用线程池TheadPoolExecutors,其中线程池的创建有两种方式:一种偷懒的做法...

  • Java多线程知识点

    1.java中实现多线程的几种方式 java中实现多线程的方式主要有两种,第一种是继承Thread类,第二种是实现...

  • Java中的多线程实现方式

    Java中的多线程实现方式 在我们的开发的过程中,常常会碰到多线程的问题,对于多线程的实现方式主要有两种:实现Ru...

  • java基础-多线程

    java线程池的实现 ThreadPoolExecutor java线程池几个参数 corePoolSize当线程...

  • JAVA多线程知识体系

    JAVA并发知识库JAVA线程实现/创建方式4种线程池线程生命周期(状态)终止线程4种方式sleep与wait 区...

  • 线程实现的方法,sleep和wait的区别

    java提供继承Thread类和实现runnable接口这两种方式来实现线程Java中sleep和wait的区别:...

网友评论

    本文标题:Java中线程池实现的两种方式

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