作者平台:
| CSDN:https://blog.csdn.net/qq_41153943(ID:江夏、)
| 掘金:https://juejin.cn/user/651387938290686(ID:jiangxia_1024)
| 知乎:https://www.zhihu.com/people/1024-paper-96(ID:江夏)
| GitHub:https://github.com/JiangXia-1024?tab=repositories
| 微信公众号:1024笔记
本文一共2496字,预计阅读15分钟
Java中的线程(Thread)是指程序执行的一个路径,它是一种轻量级的进程,用于执行特定的任务。每个Java应用都至少有一个线程,即主线程,当Java应用启动时,主线程会自动开启。
Java中的线程是通过java.lang.Thread类来实现的。在Java中,创建线程主要有两种方式:
1. 1、继承Thread类:
- 定义一个继承Thread类的子类;
- 重写Thread类的run()方法,该方法是线程的入口点;
- 实例化该子类,并调用start()方法,start()方法将启动新的线程,并执行run()方法内的代码。
例如:
public class MyThread extends Thread {public void run() {// 线程要执行的代码}}// 创建并启动新线程MyThread thread = new MyThread();thread.start();
1.2、 实现Runnable接口:
- 定义一个实现Runnable接口的类;
- 实现Runnable接口中的run()方法;
- 创建该类的实例,并将其作为参数传递给Thread类的构造函数;
- 调用start()方法来启动线程。
例如:
public class MyRunnable implements Runnable {public void run() {// 线程要执行的代码}}// 创建Runnable对象MyRunnable runnable = new MyRunnable();// 创建并启动新线程Thread thread = new Thread(runnable);thread.start();
在Java中,多线程的使用可以提高程序的执行效率,特别是对于一些需要大量计算或I/O等待的任务来说,使用多线程可以充分利用CPU资源,并提高程序响应速度。
2、线程池
Java中的线程池是一种可以管理和复用多个线程的机制。它主要包含两个组件:任务队列和线程池。任务队列用于存储等待执行的任务,而线程池则负责从任务队列中取出任务,创建线程并执行任务。
在Java中,线程池通过 Executor 框架提供支持。Java中的Executor被设计成一个顶层接口,用于实现不同的线程调度策略。Executors类是Executor框架的工厂类,可以在应用程序中方便地创建和管理线程池。常见的线程池类型包括:
1. FixedThreadPool:固定大小的线程池,线程数固定,线程池中的线程始终保持不变。如果某个任务进入任务队列后无法立即执行,则必须等待其他任务完成后才能执行。
2. CachedThreadPool:可缓存的线程池,根据需要创建新线程,但在有空闲线程时会重用先前构建的线程。当线程池中的线程长时间未使用且满足回收条件时(JVM会自动判断),会被移出线程池,直到下次有任务需要执行时再重新创建新线程。
3. SingleThreadExecutor:单一线程线程池,只有一个线程在工作,逐个执行任务。
4. ScheduledThreadPool:具有定期执行任务和延迟执行任务的固定线程池大小。
Java 中使用线程池的代码示例如下:
// 创建固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(10);// 创建一个需要执行的任务Runnable task = new Runnable() {@Overridepublic void run() {// 执行一些操作,例如输出当前线程名字System.out.println("当前线程:" + Thread.currentThread().getName());}};// 提交任务到线程池中executor.submit(task);// 最后关闭线程池executor.shutdown();
在上面的示例中,首先使用Executors.newFixedThreadPool()方法创建了一个固定大小为 10 的线程池。然后创建了一个需要执行的任务,它会输出当前线程名字。接着通过executor.submit()方法将任务提交给线程池处理。最后,使用 executor.shutdown()方法关闭线程池。
使用线程池可以避免重复创建、销毁线程的开销,提高程序的性能。同时,线程池还可以帮助我们控制并发度,防止由于线程数量过多而造成系统负载过高的问题。线程池也可以灵活地配置一些参数,例如线程数、线程超时时间等,以最大限度地满足应用程序对线程处理的管理需求。
3、线程池ThreadPoolExecutor原理
Java中的线程池是通过 Executor 框架提供支持的,其中 ThreadPoolExecutor 是 Executor 的一个实现类。ThreadPoolExecutor 可以更加灵活地配置线程池的参数。
ThreadPoolExecutor 主要有下面几个构造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
它们都具有相同的核心参数:
- corePoolSize:核心线程数。
- maximumPoolSize:线程池最大同时执行的线程数。
- keepAliveTime:空闲线程等待新任务的最长时间。
- unit:keepAliveTime 参数的时间单位。
- workQueue:阻塞队列,用于存储待执行的任务。
- threadFactory:线程工厂,用于创建线程。
- handler:拒绝策略,用于处理新任务提交时无法添加到阻塞队列中的情况。
ThreadPoolExecutor 控制着多个并发执行的任务,可以将一个线程池分成三部分:
1. 任务队列。当线程池中所有的线程均处于活动状态时,新任务将会在任务队列中等待。
2. 线程池本身。ThreadPoolExecutor 实例维护着一个固定大小的线程数,这些线程已经被创建出来并且准备好接受新的任务。
3. 任务拒绝处理器。当任务不能被添加到线程池或执行队列中时,将由任务拒绝处理器进行处理。
ThreadPoolExecutor 的原理是:通过配置一些参数,可以灵活控制线程池中的线程数量、任务队列容量以及何时创建和销毁线程等操作,避免了频繁地创建、销毁线程带来的性能损失,并且可以更好地管理线程的开销和时间,达到提高程序性能和可维护性的目的。
下面是 ThreadPoolExecutor 的使用示例:
// 创建一个固定大小为10的线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(10, // 核心线程池大小20, // 最多允许20个线程同时执行60L, // 空闲线程等待新任务的最长时间TimeUnit.SECONDS, // 时间单位(秒)new ArrayBlockingQueue<>(1000), // 等待队列(容量为1000)new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用者运行策略);// 提交任务到线程池中executor.submit(() -> {try {Thread.sleep(1000);System.out.println("Hello, world!");} catch (InterruptedException e) {e.printStackTrace();}});// 关闭线程池executor.shutdown();
在上面的示例中,首先通过构造方法创建了一个固定大小为 10 的线程池executor,它最多允许 20 个线程同时执行,并且空闲线程等待新任务的最长时间为 60 秒。任务队列是一个容量为 1000 的有界阻塞队列。拒绝策略采用了CallerRunsPolicy,当线程池无法处理新任务时,会由提交该任务的主线程直接运行任务。
接着,通过executor.submit()方法提交了一个任务到线程池中。这个任务会睡眠 1 秒并输出 "Hello, world!"。
最后,通过executor.shutdown()方法关闭了线程池。
4、总结
在使用线程池时,需要根据具体的业务场景选择合适的线程池类型和参数,以达到更好地控制并发度、提高程序性能等目的。
最后感谢大家的关注!
-END-
-
SpringCloud系列:OpenFeign组件
-
SpringCloud系列:如何使用JWT进行身份验证
-
SpringCloud系列:服务雪崩、服务熔断、服务降级
-
SpringCloud系列:Hystrix Dashboard的简单使用
-
SpringCloud系列:服务网关组件Gateway(下) -
SpringCloud系列:服务网关组件Gateway(上)
本篇文章来源于微信公众号:作者:原创 江夏
转载地址:https://mp.weixin.qq.com/s/4qqvrta3h61RZ7zp1voIOQ
微信扫描下方的二维码阅读本文

Comments NOTHING