Java 创建线程的方式
在 Java 中,有多种方式可以创建线程。以下是一些常用的创建线程的方式:
1. 继承 Thread
类
你可以通过继承 Thread
类并重写 run()
方法来创建线程。
示例:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running!");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
- 实现
Runnable
接口
通过实现 Runnable 接口来创建线程,并将其传递给 Thread 类的构造函数。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running!");
}
}
public class Main {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start(); // 启动线程
}
}
3. 使用线程池( ExecutorService
)
这是日常开发中最常用的方式
对于大规模的多线程任务,推荐使用线程池(ExecutorService)来管理线程。线程池可以重用线程,避免了频繁创建和销毁线程的开销。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);
// 提交任务
executorService.submit(() -> System.out.println("Thread is running!"));
// 关闭线程池
executorService.shutdown();
}
}
4. 使用匿名内部类
你可以使用匿名内部类的方式实现 Runnable
接口,这种方式更加简洁。
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread is running!");
}
});
thread.start(); // 启动线程
}
}
5. 使用 Lambda 表达式(Java 8及以上)
从 Java 8 开始,你可以使用 Lambda 表达式来实现 Runnable
接口,进一步简化代码。
public class Main {
public static void main(String[] args) {
Runnable task = () -> System.out.println("Thread is running!");
Thread thread = new Thread(task);
thread.start(); // 启动线程
}
}
对比
创建方式 | 优点 | 缺点 |
---|---|---|
继承 Thread 类 |
简洁直接,适用于不需要继承其他类的场景。 | 如果已继承了其他类,则不能再继承 Thread 类。 |
实现 Runnable 接口 |
更灵活,适合同时继承其他类,Runnable 可用于线程池。 |
需要更多的代码实现,较 Thread 类复杂。 |
匿名内部类 | 代码简洁,适用于临时任务。 | 对复杂的逻辑不够清晰。 |
Lambda 表达式 | 更加简洁,适合函数式编程风格。 | 仅适用于 Java 8 及以上版本。 |
线程池 (ExecutorService ) |
能有效管理线程,避免频繁创建销毁线程,提高资源利用率。 | 需要额外的配置和管理,适合任务较多的场景。 |
线程池工具类的使用
日常开发中,涉及到多线程的功能大部分情况下都是使用线程池的方式ExecutorService
来创建线程。线程池可以重用线程,避免了频繁创建和销毁线程的开销,但创建线程池和销毁线程池是怎么管理的呢,不合理的管理线程池对系统性能也是一个比较大的消耗,所以有了如下这个线程池工具类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
*
* @author wds
* @DateTime 2024/12/19 17:15
*/
public class ExecutorServiceUtils {
private static ExecutorService executorService;
/**
* 初始化线程池 默认
*/
public static synchronized void init() {
// 默认大小为 CPU 核数的2倍
init(Runtime.getRuntime().availableProcessors() * 2);
}
/**
* 初始化线程池
*
* @param threadPoolSize 线程池大小
*/
public static synchronized void init(Integer threadPoolSize) {
if (executorService == null || executorService.isShutdown()) {
executorService = Executors.newFixedThreadPool(threadPoolSize);
}
}
/**
* 获取线程池实例
*/
public static ExecutorService get() {
return executorService;
}
/**
* 提交任务到线程池
*
* @param task 任务
*/
public static void submit(Runnable task) {
if (executorService == null || executorService.isShutdown()) {
// 如果线程池为空或已关闭,重新初始化线程池
init();
}
executorService.submit(task);
}
/**
* 关闭线程池
* 应用关闭时调用
*/
public static synchronized void shutdown() {
if (executorService != null) {
try {
executorService.shutdown();
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("线程池未能在规定时间内停止");
}
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
当你需要用到这个工具类的时候,在对应的模块启动时调用
init
初始化线程池方法,服务关闭时调用shutdown
关闭线程池方法,即可实现即插即用。如:
import com.sato.mini.common.core.util.ExecutorServiceUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @author wds
* @DateTime: 2024/12/19 17:17
*/
@Component
public class ExecutorServiceConfig {
@PostConstruct
public void init() {
// 在应用启动时初始化线程池
ExecutorServiceUtils.init(8);
}
// 关闭线程池
@PreDestroy
public void shutdown() {
ExecutorServiceUtils.shutdown();
}
}