多线程是 Java 中非常重要的一部分,在现代软件开发中扮演着举足轻重的角色。Java 提供了强大的 Thread
类来处理并发任务。本文将介绍几种创建和管理线程的方法,带你快速掌握这些小技巧,并且教你如何优雅地使用多线程技术提升程序效率。
一、什么是线程?
线程是进程中最小的执行单位。Java 是多线程编程语言,可以同时执行多个线程任务,从而提升程序执行效率。每个 Java 程序至少有一个线程:主线程,它是由 JVM 启动的。除此之外,我们可以创建多个子线程来处理不同的任务。
二、创建线程的几种方式
1. 继承 Thread
类
继承 Thread
类是创建线程最直接的一种方式。我们可以通过继承 Thread
类并重写其中的 run()
方法,来定义线程的行为。
// 方式一:继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
}
}
public class ThreadExample1 {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
thread1.start(); // 启动线程
}
}
输出结果:
Thread-0 正在执行任务
代码解析:
- 我们定义了一个
MyThread
类,继承自Thread
类,并重写了run()
方法来描述线程的任务。 - 使用
start()
方法来启动线程,它会调用run()
方法并执行其中的逻辑。
2. 实现 Runnable
接口
除了继承 Thread
类,Java 还提供了 Runnable
接口来定义线程任务。通过实现 Runnable
接口,我们可以将线程任务与线程分开,拥有更好的代码灵活性。
// 方式二:实现 Runnable 接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
}
}
public class ThreadExample2 {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread2 = new Thread(runnable);
thread2.start(); // 启动线程
}
}
输出结果:
Thread-0 正在执行任务
代码解析:
- 我们定义了一个
MyRunnable
类并实现了Runnable
接口,重写run()
方法。 - 在
main
方法中,我们通过new Thread(runnable)
创建了一个线程对象,并通过start()
方法启动线程。
3. 使用 Lambda 表达式
如果你使用的是 Java 8 及以上版本,可以利用 Lambda 表达式简化代码,尤其是在使用 Runnable
接口时。
// 方式三:使用 Lambda 表达式
public class ThreadExample3 {
public static void main(String[] args) {
Thread thread3 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
});
thread3.start(); // 启动线程
}
}
输出结果:
Thread-0 正在执行任务
代码解析:
- 使用 Lambda 表达式简化了
Runnable
接口的实现,省去了定义单独类的步骤,使代码更加简洁。
三、线程池创建多线程
在某些情况下,直接创建线程的方式可能不太高效,尤其是在大量并发任务的情况下。Java 提供了线程池 ExecutorService
来管理线程,避免频繁创建和销毁线程带来的开销。
1. 使用 ExecutorService
创建线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务 " + taskId);
});
}
executor.shutdown(); // 关闭线程池
}
}
输出结果:
pool-1-thread-1 正在执行任务 1
pool-1-thread-2 正在执行任务 2
pool-1-thread-3 正在执行任务 3
pool-1-thread-1 正在执行任务 4
pool-1-thread-2 正在执行任务 5
代码解析:
- 通过
Executors.newFixedThreadPool()
创建一个固定大小的线程池。 - 线程池管理线程的创建和销毁,避免了频繁启动线程的开销。
shutdown()
方法用于关闭线程池,确保所有任务执行完毕后终止。
四、线程的中断与终止
在 Java 中,线程的中断并不会直接终止线程,而是通过中断标志位来通知线程自行终止。
1. 中断线程
public class InterruptExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("正在执行任务 " + i);
Thread.sleep(1000); // 模拟耗时任务
}
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
});
thread.start();
// 主线程等待 2 秒后中断子线程
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt(); // 中断线程
}
}
输出结果:
正在执行任务 1
正在执行任务 2
线程被中断
代码解析:
- 调用
interrupt()
方法可以设置线程的中断标志位,当线程在sleep()
、wait()
等操作时检测到中断,会抛出InterruptedException
异常,从而终止任务。
2. 自定义中断检查
线程中的一些任务可能不会自动响应中断请求,因此我们可以在任务内部手动检查线程的中断状态,确保线程在必要时能正确终止。
public class CustomInterruptExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程被中断,停止执行任务");
return;
}
System.out.println("正在执行任务 " + i);
}
});
thread.start();
// 主线程等待 2 秒后中断子线程
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt(); // 中断线程
}
}
输出结果:
正在执行任务 1
正在执行任务 2
线程被中断,停止执行任务
代码解析:
- 使用
Thread.currentThread().isInterrupted()
方法检查线程的中断状态,根据结果决定是否终止任务。
五、守护线程
守护线程是程序在后台运行的线程,它不会影响程序的正常运行。当所有非守护线程结束时,守护线程会自动终止。
创建守护线程
public class DaemonThreadExample {
public static void main(String[] args) {
Thread daemonThread = new Thread(() -> {
while (true) {
System.out.println("守护线程正在运行...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
daemonThread.setDaemon(true); // 设置为守护线程
daemonThread.start();
// 主线程休眠 3 秒后结束
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
输出结果:
守护线程正在运行...
守护线程正在运行...
守护线程正在运行...
主线程结束
代码解析:
setDaemon(true)
将线程设置为守护线程。- 当主线程结束时,守护线程也随之终止。
六、总结
本文介绍了多种创建和管理 Java 线程的方式,包括继承 Thread
类、实现 Runnable
接口、使用 Lambda 表达式、线程池以及守护线程。此外,还介绍了如何中断线程和自定义中断检查。
多线程编程是 Java 的强大功能之一,掌握这些技巧将大大
提升你在并发编程中的效率和灵活性。随着你不断深入学习和实践,相信你能够驾驭更复杂的并发任务,编写出高效、稳定的多线程程序。