在 Java SE 中,多线程是并发编程的核心,能够有效地提升程序性能,特别是在 CPU 密集型或 I/O 密集型的应用中。Java 为开发者提供了强大的多线程支持,包括 Thread
类和 Runnable
接口。多线程的实现可以让多个任务同时进行,从而提高系统的效率。
1. 线程的基本概念
线程(Thread) 是操作系统能够进行运算调度的最小单位。每个线程都有自己独立的执行路径,程序中可能同时有多个线程并行执行。Java 中的线程可以通过 Thread
类或 Runnable
接口来创建和控制。
线程的状态
Java 中的线程有五种基本状态:
- 新建(New):线程对象被创建,但尚未开始执行。
- 就绪(Runnable):线程已准备好并等待操作系统的调度来执行。
- 运行(Running):线程正在执行任务。
- 阻塞(Blocked):线程被阻塞,等待某个资源的可用(例如 I/O 操作)。
- 死亡(Terminated):线程执行完毕或被终止。
2. 创建线程的两种方式
2.1 继承 Thread 类
Thread
类是 Java 中用于创建线程的基本类。通过继承 Thread
类并重写其 run
方法来定义线程执行的任务。
示例:
class MyThread extends Thread {
@Override
public void run() {
// 执行任务
System.out.println("Thread is running");
}
public static void main(String[] args) {
MyThread thread = new MyThread(); // 创建线程对象
thread.start(); // 启动线程
}
}
解释:
MyThread
类继承了Thread
类,并重写了run()
方法,run()
方法中包含了线程需要执行的任务。start()
方法用于启动线程,内部会调用run()
方法。
2.2 实现 Runnable 接口
如果类已经继承了其他类,不能再继承 Thread
类,这时我们可以通过实现 Runnable
接口来实现线程。Runnable
接口中的 run()
方法定义了线程执行的任务。
示例:
class MyRunnable implements Runnable {
@Override
public void run() {
// 执行任务
System.out.println("Runnable thread is running");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable); // 创建线程对象
thread.start(); // 启动线程
}
}
解释:
MyRunnable
实现了Runnable
接口,并重写了run()
方法。Thread
类接收一个Runnable
对象并启动执行。
3. 线程的生命周期
线程的生命周期从新建到终止经过多个状态。
- 新建状态:当线程对象被创建后,处于新建状态,此时并未开始执行。
- 就绪状态:当调用
start()
方法时,线程进入就绪状态,等待操作系统的调度。 - 运行状态:当操作系统分配到 CPU 时间片时,线程进入运行状态,开始执行
run()
方法中的任务。 - 阻塞状态:线程可能因为 I/O 操作或等待资源而进入阻塞状态。
- 死亡状态:线程执行完毕或被终止时,进入死亡状态,生命周期结束。
4. 常见的线程方法
Java Thread
类提供了一些常用方法来控制线程的行为:
start()
:启动线程,调用线程的run()
方法。run()
:定义线程的执行任务。sleep(long millis)
:使当前线程休眠指定的毫秒数,暂停执行。yield()
:使当前线程暂停执行,调度其他线程。join()
:使当前线程等待,直到目标线程执行完毕。interrupt()
:中断当前线程的执行。
示例:
class MyThread extends Thread {
@Override
public void run() {
try {
// 线程休眠 2 秒
System.out.println("Thread started...");
Thread.sleep(2000);
System.out.println("Thread resumed...");
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
}
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start(); // 启动线程
thread.join(); // 等待线程执行完毕
System.out.println("Main thread finished");
}
}
解释:
sleep(2000)
使线程暂停执行 2 秒钟。join()
方法使主线程等待MyThread
完成后再执行。
5. 线程同步
在多线程编程中,多个线程可能会共享某些资源,如果不加以控制,就会导致数据不一致的问题。同步(synchronization) 机制可以避免这种情况。
5.1 使用 synchronized
关键字
synchronized
关键字用于方法或代码块,可以确保在同一时刻只有一个线程访问该资源。
示例:
class Counter {
private int count = 0;
// 使用 synchronized 保证线程安全
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SyncExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount()); // 输出: 2000
}
}
解释:
increment()
方法使用了synchronized
关键字,确保同一时刻只有一个线程能够访问它。- 通过
join()
确保两个线程执行完毕后再输出最终结果。
5.2 同步代码块
如果只需要同步某一段代码,可以使用同步代码块,避免整个方法被锁住,提高程序效率。
示例:
class Counter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
6. 线程池
线程池是 Java 中用来管理线程的一种方式,能有效地复用线程、控制线程数量、提高效率。Java 提供了 Executor
框架来实现线程池。
6.1 创建线程池
使用 Executors
工厂类来创建常见的线程池:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
// 提交任务到线程池
pool.submit(() -> {
System.out.println("Task 1");
});
pool.submit(() -> {
System.out.println("Task 2");
});
pool.submit(() -> {
System.out.println("Task 3");
});
pool.shutdown(); // 关闭线程池
}
}
解释:
newFixedThreadPool(3)
创建了一个包含 3 个线程的线程池。submit()
方法用于提交任务,任务将在空闲线程中执行。- 使用
shutdown()
方法来关闭线程池。
7. 总结
Java SE 提供了丰富的多线程支持,通过 Thread
类和 Runnable
接口可以方便地实现多线程。为了实现线程安全,可以使用 synchronized
关键字来避免资源的竞态条件。而线程池则提供了一种高效的线程管理方式,适合于处理大量短期的任务。
- 创建线程:可以通过继承
Thread
类或实现Runnable
接口来创建线程。 - 线程同步:
synchronized
关键字可以用于方法和代码块,确保线程安全。 - 线程池:线程池管理可以提高性能,并避免线程的频繁创建与销毁。
多线程是 Java 中非常重要的编程概念,掌握了多线程编程后,可以处理复杂的并发任务,提高系统的性能。
发表回复