Java 多线程基础讲解

  • 多线程是 Java 编程中的重要概念,它允许程序同时执行多个任务,从而提高程序的效率和性能。本文将介绍 Java 中多线程的基础知识,包括线程的创建、同步、通信等内容。

1. 什么是线程?

  • 线程是程序执行的最小单元。一个进程可以包含多个线程,每个线程可以独立执行不同的任务。多线程的优势在于可以充分利用 CPU 资源,提高程序的并发性。

2. 创建线程的两种方式

  • 在 Java 中,创建线程有两种主要方式:

方式一:继承 Thread

  • 通过继承 Thread 类并重写 run() 方法来创建线程。
1
2
3
4
5
6
7
8
9
10
11
12
13
class MyThread extends Thread {  // 定义一个继承 Thread 的类
@Override
public void run() { // 重写 run 方法,定义线程执行的任务
System.out.println("线程运行中: " + Thread.currentThread().getName()); // 打印当前线程名称
}
}

public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread(); // 创建线程对象
thread.start(); // 启动线程,调用 run 方法
}
}

方式二:实现 Runnable 接口

  • 通过实现 Runnable 接口并实现 run() 方法来创建线程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyRunnable implements Runnable {  // 定义一个实现 Runnable 接口的类
@Override
public void run() { // 实现 run 方法,定义线程执行的任务
System.out.println("线程运行中: " + Thread.currentThread().getName()); // 打印当前线程名称
}
}

public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable()); // 创建线程对象,传入 Runnable 实例
thread.start(); // 启动线程,调用 run 方法
}
}
推荐使用 Runnable 接口,因为 Java 不支持多继承,而实现接口可以避免继承的局限性。

3. 线程的生命周期

  • 线程的生命周期包括以下几个状态:

    • 新建(New):线程对象被创建,但尚未启动。

    • 就绪(Runnable):线程已经启动,等待 CPU 调度。

    • 运行(Running):线程正在执行任务。

    • 阻塞(Blocked):线程因为某些原因(如等待锁)暂时停止执行。

    • 终止(Terminated):线程执行完毕或被强制终止。

4. 线程同步

  • 多线程环境下,多个线程可能同时访问共享资源,导致数据不一致的问题。Java 提供了以下机制来解决线程同步问题:

  • 使用 synchronized 关键字

  • synchronized 可以修饰方法或代码块,确保同一时间只有一个线程可以访问共享资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Counter {  // 定义一个计数器类
private int count = 0; // 共享变量

public synchronized void increment() { // 使用 synchronized 修饰方法
count++; // 对共享变量进行操作
}

public int getCount() { // 获取计数器的值
return count;
}
}

public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter(); // 创建计数器对象

Thread t1 = new Thread(() -> { // 创建线程 t1
for (int i = 0; i < 1000; i++) {
counter.increment(); // 调用 increment 方法
}
});

Thread t2 = new Thread(() -> { // 创建线程 t2
for (int i = 0; i < 1000; i++) {
counter.increment(); // 调用 increment 方法
}
});

t1.start(); // 启动线程 t1
t2.start(); // 启动线程 t2
t1.join(); // 等待线程 t1 执行完毕
t2.join(); // 等待线程 t2 执行完毕

System.out.println("最终计数: " + counter.getCount()); // 打印最终计数
}
}

使用 ReentrantLock

  • ReentrantLock 是 java.util.concurrent.locks 包中的一个类,提供了更灵活的锁机制。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    import java.util.concurrent.locks.Lock; // 导入 Lock 接口
    import java.util.concurrent.locks.ReentrantLock; // 导入 ReentrantLock 类

    class Counter { // 定义一个计数器类
    private int count = 0; // 共享变量
    private Lock lock = new ReentrantLock(); // 创建 ReentrantLock 对象

    public void increment() { // 定义 increment 方法
    lock.lock(); // 加锁
    try {
    count++; // 对共享变量进行操作
    } finally {
    lock.unlock(); // 释放锁
    }
    }

    public int getCount() { // 获取计数器的值
    return count;
    }
    }

5. 线程通信

  • 线程之间可以通过 wait()、notify() 和 notifyAll() 方法进行通信。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Message {  // 定义一个消息类
private String message; // 消息内容
private boolean empty = true; // 标记消息是否为空

public synchronized String read() { // 读取消息的方法
while (empty) { // 如果消息为空,等待
try {
wait(); // 线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
empty = true; // 标记消息为空
notifyAll(); // 唤醒所有等待的线程
return message; // 返回消息内容
}

public synchronized void write(String message) { // 写入消息的方法
while (!empty) { // 如果消息不为空,等待
try {
wait(); // 线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
empty = false; // 标记消息不为空
this.message = message; // 设置消息内容
notifyAll(); // 唤醒所有等待的线程
}
}

public class Main {
public static void main(String[] args) {
Message message = new Message(); // 创建消息对象

Thread writer = new Thread(() -> { // 创建写线程
String[] messages = {"Hello", "World", "Java"}; // 定义消息数组
for (String msg : messages) {
message.write(msg); // 写入消息
}
});

Thread reader = new Thread(() -> { // 创建读线程
for (int i = 0; i < 3; i++) {
System.out.println("读取消息: " + message.read()); // 读取消息
}
});

writer.start(); // 启动写线程
reader.start(); // 启动读线程
}
}

6. 线程池

  • Java 提供了线程池(ExecutorService)来管理线程,避免频繁创建和销毁线程的开销。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.util.concurrent.ExecutorService; // 导入 ExecutorService 接口
import java.util.concurrent.Executors; // 导入 Executors 工具类

public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池

for (int i = 0; i < 10; i++) { // 提交 10 个任务
Runnable task = () -> { // 定义任务
System.out.println("任务执行: " + Thread.currentThread().getName()); // 打印当前线程名称
};
executor.execute(task); // 提交任务到线程池
}

executor.shutdown(); // 关闭线程池
}
}

7. 总结

  • 多线程可以提高程序的并发性和性能。

  • 创建线程可以通过继承 Thread 类或实现 Runnable 接口。

  • 线程同步可以通过 synchronized 或 ReentrantLock 实现。

  • 线程通信可以通过 wait()、notify() 和 notifyAll() 实现。

  • 线程池可以高效管理线程资源。

  • 希望这篇文档对你理解 Java 多线程有所帮助!如果有任何问题,欢迎留言讨论。