Java线程池的使用方法

下面就是Java线程池的使用攻略。

什么是线程池

线程池是多线程编程的一种技术,它是一种旨在优化线程资源使用和管理的实现方式。它重用现有线程来执行任务,因此它可以大大减少线程的创建和销毁的开销。同时,它可以有效地控制并发,避免因线程过多导致CPU过度切换,从而提高系统性能和稳定性。

在Java中,线程池是通过java.util.concurrent包实现的。实际上,Java线程池就是一个线程池的管理器,它维护一个线程池,其中的线程可以执行任何实现了Runnable接口的对象。

如何使用线程池

Java线程池的使用过程包括以下几个步骤:

  1. 创建一个线程池对象

线程池的创建有两种方式:

// 使用 Executors 来创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);

// 使用 ThreadPoolExecutor 来创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,          // 核心线程数
    10,         // 最大线程数
    200,        // 线程空闲时的存活时间
    TimeUnit.MILLISECONDS, // 存活时间的时间单位
    new ArrayBlockingQueue<Runnable>(5), // 任务队列
    new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
);

上面的示例代码中,第一种方式使用了Executors工厂类的静态方法来创建线程池;第二种方式则是手动创建ThreadPoolExecutor对象,并对其进行一些配置。

  1. 提交任务到线程池

将任务提交到线程池中,线程池会从池中的线程中选择一个来执行该任务。

executorService.execute(new Runnable() {
    @Override
    public void run() {
        // do something
    }
});

上面的示例代码中,通过执行execute()方法将Runnable对象提交给线程池。

  1. 关闭线程池

当不再需要使用线程池时,可以将其关闭以释放资源。

executorService.shutdown();

上面的示例代码中,通过shutdown()方法来关闭线程池。

线程池中的参数

Java线程池包含多个参数,下面是其中一些关键的参数。

  1. 核心线程数

线程池能够同时执行的最大线程数。在没有任务执行时,线程池中保持的线程数。

  1. 最大线程数

线程池能够容纳的最大线程数。当核心线程数达到最大值时,新来的任务会被放在任务队列中等待执行。如果当前任务队列已满,那么新来的任务将创建新线程执行。当最大线程数也到达上限时,则会根据拒绝策略来处理超过最大线程数限制的任务。

  1. 线程的存活时间

当线程空闲时,即没有任务可执行时,它会存活一段时间并保持其线程的状态。存活时间可以指定,如果达到存活时间还没有任务可执行,则该线程会被杀死。

  1. 任务队列

任务队列是一个FIFO队列,用于存放等待执行的任务。如果有新的任务需要执行,但是当前线程数已经达到了最大值,那么它将被加入等待队列。当线程池中有空闲的线程时,它将从该队列中取出待执行的任务。任务队列可以是有界队列,也可以是无界队列。有界队列有数量上限,超过数量上限后再添加任务时,任务将被拒绝。

  1. 拒绝策略

当线程池中的线程数已达到最大值,并且队列也已满时,新来的任务就会被拒绝。此时就需要一个拒绝策略来处理这些被拒绝的任务。Java提供了4种预先定义的拒绝策略:

  • AbortPolicy:直接丢弃任务,并抛出RejectedExecutionException异常。
  • CallerRunsPolicy:使用提交任务的线程去执行该任务。如果提交任务的线程池已经被销毁,则直接丢弃任务。
  • DiscardOldestPolicy:丢弃最早加入等待队列的任务,然后将新任务加入队列。
  • DiscardPolicy:丢弃任务,不做任何处理。

示例代码

下面是一个使用Java线程池的示例代码,用于计算一个数组中所有元素的和。

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

public class ThreadPoolDemo {

    public static void main(String[] args) {
        // 创建一个固定大小的线程池,大小为5
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 创建一个包含30个元素的数组
        int[] array = new int[30];
        for (int i = 0; i < array.length; i++) {
            array[i] = i + 1;
        }

        // 计算所有元素的和
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            int value = array[i];

            // 提交任务到线程池
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    sum += value;
                }
            });
        }

        // 关闭线程池
        executor.shutdown();

        // 等待线程池中的任务全部执行结束
        while (!executor.isTerminated()) {
            Thread.yield();
        }

        // 输出所有元素的和
        System.out.println("sum = " + sum);
    }
}

上面的代码中,使用newFixedThreadPool()方法创建一个固定大小的线程池,大小为5。然后创建一个包含30个元素的数组,随后将每个元素通过execute()方法提交给线程池中的线程并计算元素的和。最后关闭线程池并等待其执行完所有任务,输出所有元素的和。

另外,为了说明线程池中的参数,下面是一个更加详细的示例代码:

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

public class ThreadPoolDemo {

    public static void main(String[] args) {
        // 创建一个大小为5的核心线程池,最大线程数为10,线程存活时间200毫秒,使用有界队列,拒绝策略是CallerRunsPolicy
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5,          // 核心线程数
                10,         // 最大线程数
                200,        // 线程空闲时的存活时间
                TimeUnit.MILLISECONDS, // 存活时间的时间单位
                new ArrayBlockingQueue<Runnable>(5), // 任务队列
                new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
        );

        // 提交10个任务给线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("start task " + taskId);

                        // 任务执行2秒,模拟耗时操作
                        Thread.sleep(2000);

                        System.out.println("end task " + taskId);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            executor.submit(task);
        }

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

上面的代码中,手动创建了一个角色线程池,大小为5,最大线程数为10,线程存活时间为200毫秒,使用有界队列。然后提交了10个任务,当线程池的多个线程同时执行任务时,可以很清楚地看到它们的执行过程。最后关闭了线程池。

希望这篇攻略对Java线程池的使用方式有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程池的使用方法 - Python技术站

(0)
上一篇 2023年4月19日
下一篇 2023年4月19日

相关文章

  • Java之类和对象的概念

    Java是一种面向对象的编程语言,而类和对象则是Java中最基本的概念。下面是Java中类和对象的使用方法攻略: 类和对象的概念 类是Java中一种定义自定义类型的机制。通常来说,一个类包含了数据域和方法。数据域是类的属性,而方法是对属性的操作。Java中所有的代码必须定义在一个类中,然后才能被执行。 在Java中,我们可以使用关键字class来定义一个类。…

    Java 2023年4月19日
    00
  • Java的数据类型和变量

    Java数据类型 Java支持8种基本数据类型,它们分别是: byte short int long float double char boolean 这些基本数据类型都有对应的包装类。包装类主要是为了方便基本数据类型的使用,比如说提供了一些实用的静态方法和常量。 下面我们来详细介绍一下Java的各种数据类型。 1. byte byte数据类型是一个8位带…

    Java 2023年4月19日
    00
  • Java的关键字和标识符

    关键字和标识符是Java中的基础概念,它们在编写Java程序中扮演着非常重要的角色。在本篇文章中,我将详细讲解Java关键字和标识符的使用方法,并提供两个具体的代码示例。 Java关键字 Java关键字是Java语言中已经预先定义好的,具有特定含义的单词。这些关键字在Java程序中具有固定的用法,不能被用作变量名或方法名等标识符。在Java中一共有50个关键…

    Java 2023年4月19日
    00
  • Java异常的处理方式

    Java中提供了异常处理机制,可以让程序更加健壮和稳定。在程序发生异常时,我们可以使用try-catch语句来捕获异常,避免程序崩溃。以下是Java异常处理的使用方法: 1. try-catch语句 try-catch语句可以用来捕获异常,让程序能够继续执行。try代码块中包含可能会发生异常的代码,catch代码块中可以处理这些异常。 try { // 可能…

    Java 2023年4月19日
    00
  • Java泛型的概念和使用

    下面是Java泛型的概念和使用攻略。 概念 Java泛型是一种参数化类型的概念,它可以让我们在定义类、方法或接口时使用参数来表示类型参数,并在使用时用实际类型参数代替类型参数。泛型的设计初衷是为了在编译时期发现类型错误,从而让程序更加健壮和可维护。 泛型的语法主要涉及以下几个部分: 类型参数:用尖括号包裹,例如<T>。 泛型类:使用类型参数定义类…

    Java 2023年4月19日
    00
  • Java中对象的创建和使用

    我来为您讲解Java中对象的创建和使用的完整攻略。 对象的创建 在Java中,对象是根据类来创建的。具体的创建过程分为以下几个步骤: 1. 定义类 首先需要定义一个类,用于描述对象具有的属性和方法。例如,下面是一个简单的类定义示例: public class Person { String name; int age; public void sayHell…

    Java 2023年4月19日
    00
  • Java的优点和缺点都有哪些

    Java是一种高级编程语言,具有丰富的特性和广泛的应用。Java有很多优点和缺点,下面我将详细讲解。 Java的优点 1. 跨平台性 Java的最大优点是跨平台性。Java程序在不同的操作系统上都可以运行,做到了”一次编写,到处运行”,这是因为Java使用了虚拟机(JVM)来运行程序,不同的操作系统只需要提供JVM即可运行Java程序。下面是一个Java跨平…

    Java 2023年4月19日
    00
  • Java之继承和接口的概念

    Java是一种面向对象的编程语言,继承和接口是面向对象语言中重要的概念之一。继承和接口都可以用来扩展类的功能,但它们之间有一些显著的不同。下面将详细介绍Java中继承和接口的概念及其使用方法。 继承 继承是指一个类可以基于另一个类的定义来创建,继承的类称为子类,被继承的类称为父类或超类。子类可以复用父类中的代码,并在此基础上添加新的方法和数据成员。 语法 J…

    Java 2023年4月19日
    00
合作推广
合作推广
分享本页
返回顶部