【Java菜鸟学习进阶路线】Java进阶知识篇之线程池的使用

Java的线程池是一种简化线程管理的技术,它可以用来维护一组预分配的线程,以在处理多个任务时提高性能。在Java中,线程池是通过使用java.util.concurrent包中的ThreadPoolExecutor类来实现的。

线程池原理

当我们提交一个任务给线程池时,线程池会管理一个固定数量的线程来处理这些任务。当有新任务提交时,线程池中的某个线程会被唤醒来处理任务。
线程池中的线程是无限循环的,它们会一直等待新的任务到来。当任务到来时,它们会尝试获取一个任务,如果没有任务可用,它们会等待直到有新的任务到来。

ThreadPoolExecutor原理图

图来源
美团技术团队

线程池的好处

  1. 降低资源消耗:线程池可以避免频繁地创建和销毁线程,从而减少系统资源的消耗。

  2. 提高响应速度:线程池中的任务可以并行执行,从而提高系统的响应速度。

  3. 提高线程的可管理性:线程池可以对线程进行统一的分配、调度和监控,从而提高线程的可管理性。

如何使用线程池

在Java中,创建线程池需要使用ThreadPoolExecutor类。下面是一个简单的代码示例,用于创建和使用一个线程池:

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

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

        // 提交一个实现了Runnable接口的任务
        for (int i = 0; i < 10; i++) {
            executorService.submit(new RunnableTask());
        }

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

class RunnableTask implements Runnable {
    @Override
    public void run() {
        System.out.println("任务执行中,当前线程:" + Thread.currentThread().getName());
    }
}

Java的常用线程池实现

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

public class NewCachedThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个缓存线程池,最大线程数为10
        ExecutorService executorService = Executors.newCachedThreadPool();

        // 提交10个任务到线程池
        for (int i = 0; i < 10; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程名:" + Thread.currentThread().getName() + ",执行任务");
                }
            });
        }

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

  1. newFixedThreadPool: 创建一个定长线程池,可以控制线程的最大并发数,以保证系统的稳定性。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

        // 提交10个任务到线程池
        for (int i = 0; i < 10; i++) {
            Runnable task = new MyTask(i);
            executorService.submit(task);
        }

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

class MyTask implements Runnable {
    private int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Task " + taskId + " is running by thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Task " + taskId + " is completed by thread " + Thread.currentThread().getName());
    }
}

  1. newSingleThreadExecutor: 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        // 创建一个只有一个工作线程的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // 提交一个任务到线程池
        executorService.submit(() -> {
            System.out.println("Hello from task!");
        });

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

  1. newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个具有3个线程的线程池
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);

        // 创建一个Runnable任务
        Runnable task = () -> System.out.println("执行任务:" + System.currentTimeMillis());

        // 将任务提交到线程池,设置初始延迟为1秒,每隔2秒执行一次
        scheduledExecutorService.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);

        // 在主线程休眠5秒后,关闭线程池
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        scheduledExecutorService.shutdown();
    }
}

  1. newWorkStealingPool: Java 7 加入的 Fork/Join 新型线程池,是一个可以并行执行任务的线程池。
import java.util.concurrent.*;

public class WorkStealingPoolExample {
    public static void main(String[] args) {
        // 创建一个ForkJoinPool.commonPool()作为基础线程池
        ForkJoinPool commonPool = ForkJoinPool.commonPool();

        // 创建一个自定义的任务类,继承自RecursiveTask
        class CustomTask extends RecursiveTask<Integer> {
            private final int start;
            private final int end;

            public CustomTask(int start, int end) {
                this.start = start;
                this.end = end;
            }

            @Override
            protected Integer compute() {

ThreadPoolExecutor类

ThreadPoolExecutor是Java中一个非常重要的线程池实现类,它提供了一种更加灵活的方式来管理和控制线程。ThreadPoolExecutor可以自定义线程数量、任务队列、线程工厂等参数,从而实现更加高效的线程池管理。

ThreadPoolExecutor构造参数

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

  • corePoolSize:核心线程数,即线程池中始终保持的线程数量;
  • maximumPoolSize:最大线程数,即线程池中允许的最大线程数量;
  • keepAliveTime:非核心线程空闲时的存活时间;
  • unit:存活时间的单位;
  • workQueue:任务队列,用于存储待执行的任务。

如何使用

import java.util.concurrent.*;

public class ThreadPoolExecutorDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));

        // 提交10个任务到线程池
        for (int i = 0; i < 10; i++) {
            final int taskIndex = i;
            executor.execute(() -> {
                System.out.println("Task " + taskIndex + " is running by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskIndex + " is completed by " + Thread.currentThread().getName());
            });
        }

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

注意点

  1. 线程池应该根据系统资源和工作负载进行调整,以确保最佳性能。如果线程池中的线程数太少,任务可能不会得到及时处理。如果线程数太多,则会消耗过多的系统资源。

  2. 如果线程池中的一个线程崩溃,线程池应该能够自动恢复并重新创建一个新的线程来取代它。

  3. 如果线程池中的任务队列已满,并且没有可用的线程,那么新的任务应该被拒绝或排队等待。

  4. 确保在使用线程池时,每个任务都能够有效地使用线程资源。如果一个任务需要等待另一个任务完成,那么线程池的性能会受到影响。

总结

Java线程池是一种管理线程的机制,它允许我们创建和控制一定数量的线程,以执行并发任务。

下一章将介绍Java的反射机制

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值