Java 中的多线程是一个非常重要且复杂的主题。多线程允许程序同时执行多个任务,提高了应用程序的性能和响应速度。多线程编程涉及线程的创建、管理、同步和通信等多个方面。下面我将详细讲解 Java 多线程的使用。
1. 什么是线程?
线程是程序执行的最小单位,一个进程可以包含多个线程,每个线程可以执行不同的任务。线程之间共享进程的资源,但每个线程都有自己的执行栈和程序计数器。
2. 创建线程的方式
在 Java 中,有两种主要的方式来创建线程:
2.1 继承 Thread
类
通过继承 Thread
类并重写其 run()
方法,可以创建一个新的线程。
-
示例
class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running"); } } } public class ThreadExample { public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); thread1.start(); // 启动线程 thread2.start(); } }
2.2 实现 Runnable
接口
另一种更常用的创建线程的方式是实现 Runnable
接口,并将其传递给 Thread
对象。
-
示例
class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running"); } } } public class RunnableExample { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread1 = new Thread(myRunnable); Thread thread2 = new Thread(myRunnable); thread1.start(); // 启动线程 thread2.start(); } }
3. 线程的生命周期
线程的生命周期包括以下几个阶段:
- 新建 (New):线程对象被创建,但尚未调用
start()
方法。 - 就绪 (Runnable):调用
start()
方法后,线程进入就绪状态,等待 CPU 调度执行。 - 运行 (Running):线程被 CPU 调度执行,
run()
方法开始执行。 - 阻塞 (Blocked):线程因等待某些条件(如资源、锁)暂时挂起,等待条件满足后进入就绪状态。
- 终止 (Terminated):线程的
run()
方法执行完毕或因异常退出,线程进入终止状态。
4. 线程的控制
4.1 join()
方法
join()
方法允许一个线程等待另一个线程完成。
-
示例
class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class JoinExample { public static void main(String[] args) { Thread thread1 = new Thread(new MyRunnable()); Thread thread2 = new Thread(new MyRunnable()); thread1.start(); try { thread1.join(); // main 线程等待 thread1 执行完毕 } catch (InterruptedException e) { e.printStackTrace(); } thread2.start(); } }
4.2 sleep()
方法
sleep()
方法使当前线程暂停执行一段时间,让出 CPU 资源,但线程仍保持就绪状态。
-
示例
public class SleepExample { public static void main(String[] args) { Runnable runnable = () -> { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running"); try { Thread.sleep(1000); // 暂停 1 秒 } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread thread = new Thread(runnable); thread.start(); } }
4.3 interrupt()
方法
interrupt()
方法用于中断线程,通知其停止执行。
-
示例
public class InterruptExample { public static void main(String[] args) { Thread thread = new Thread(() -> { try { while (!Thread.currentThread().isInterrupted()) { System.out.println("Thread is running"); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Thread was interrupted"); } }); thread.start(); try { Thread.sleep(3000); // main 线程暂停 3 秒 } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); // 中断线程 } }
5. 线程同步
多线程环境下,如果多个线程同时访问共享资源,可能会引发数据不一致的问题。这种情况下,需要使用线程同步技术。
5.1 synchronized
关键字
synchronized
关键字用于确保某个代码块或方法在同一时刻只能被一个线程执行。
-
示例:同步方法
class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } public class SynchronizedExample { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Final count: " + counter.getCount()); } }
5.2 volatile
关键字
volatile
关键字用于确保线程每次读取变量值时,都是从主存中读取,保证了变量的可见性。
-
示例
class VolatileExample { private volatile boolean flag = true; public void run() { while (flag) { System.out.println("Thread is running"); } } public void stop() { flag = false; } public static void main(String[] args) throws InterruptedException { VolatileExample example = new VolatileExample(); Thread thread = new Thread(example::run); thread.start(); Thread.sleep(1000); example.stop(); // 停止线程 } }
6. 高级并发工具
Java 提供了一些高级并发工具类,这些类位于 java.util.concurrent
包中,常见的包括:
6.1 ExecutorService
ExecutorService
是 Java 提供的一个线程池框架,方便管理和复用线程。
-
示例
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); Runnable task = () -> { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; executorService.submit(task); executorService.submit(task); executorService.shutdown(); // 关闭线程池 } }
6.2 Callable
和 Future
Callable
接口类似于 Runnable
,但它可以返回结果,并且可以抛出异常。Future
接口用于表示 Callable
任务的异步执行结果。
-
示例
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class CallableExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Callable<Integer> callable = () -> { Thread.sleep(2000); return 42; }; Future<Integer> future = executorService.submit(callable); try { System.out.println("Future result: " + future.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } }
6.3 CountDownLatch
CountDownLatch
是一个同步工具类,它允许一个或多个线程
等待其他线程完成操作。
-
示例
import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { int count = 3; CountDownLatch latch = new CountDownLatch(count); Runnable task = () -> { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " has finished."); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); } }; for (int i = 0; i < count; i++) { new Thread(task).start(); } latch.await(); // 等待所有线程完成 System.out.println("All threads have finished."); } }
7. 总结
Java 多线程编程是一个复杂但非常强大的工具。通过线程,你可以实现并发任务,提升程序的效率。然而,线程带来的并发问题(如死锁、资源竞争等)也是编程中需要特别注意的部分。掌握线程的基本操作、同步方法和高级并发工具,可以让你在开发高性能应用程序时得心应手。