package threads;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
-
Java多线程编程演示类
-
本类演示了Java多线程编程的核心概念和常用技术,包括:
-
- 线程创建:继承Thread类 vs 实现Runnable接口
-
- 线程同步:synchronized关键字
-
- 线程通信:wait/notify机制
-
- 线程池:Executor框架
-
- 并发工具:Lock、Atomic类等
-
重要概念:
-
- 线程安全:多线程环境下数据的一致性
-
- 死锁:线程相互等待资源
-
- 线程生命周期:新建、就绪、运行、阻塞、死亡
*/
public class ThreadDemo {
/**
-
演示多线程编程的入口方法
-
该方法按顺序调用各个演示方法,展示Java多线程的核心功能
*/
public static void demo() {
// 打印演示开始信息
System.out.println(“\n=== 多线程编程演示开始 ===”);// 1. 线程创建演示 - 演示不同的线程创建方式
demonstrateThreadCreation();// 2. 线程同步演示 - 展示线程安全问题及解决方案
demonstrateThreadSynchronization();// 3. 线程通信演示 - 演示基于wait/notify的线程间通信
demonstrateThreadCommunication();// 4. 线程池演示 - 展示Executor框架的使用
demonstrateThreadPool();// 5. 并发工具演示 - 展示高级并发工具的使用
demonstrateConcurrencyTools();// 打印演示结束信息
System.out.println(“=== 多线程编程演示结束 ===\n”);
}
/**
-
演示线程创建的三种方式
-
- 继承Thread类
-
- 实现Runnable接口
-
- 使用Lambda表达式(Java 8+)
-
每种方式都创建并启动线程,并等待其执行完成
*/
private static void demonstrateThreadCreation() {
// 打印当前演示的标题
System.out.println(“\n— 线程创建演示 —”);// 方法1:继承Thread类
// 创建两个自定义线程对象
MyThread thread1 = new MyThread(“线程A”);
MyThread thread2 = new MyThread(“线程B”);// 启动线程 - 调用start()方法而不是直接调用run()
thread1.start();
thread2.start();// 等待线程执行完成 - 确保当前线程等待thread1和thread2执行完毕
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
// 打印异常堆栈信息
e.printStackTrace();
}// 方法2:实现Runnable接口
System.out.println(“\n— 实现Runnable接口 —”);
// 创建线程对象,传入Runnable实现类
Thread runnableThread1 = new Thread(new MyRunnable(“Runnable线程1”));
Thread runnableThread2 = new Thread(new MyRunnable(“Runnable线程2”));// 启动线程
runnableThread1.start();
runnableThread2.start();// 等待线程执行完成
try {
runnableThread1.join();
runnableThread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}// 方法3:使用Lambda表达式(Java 8+)
System.out.println(“\n— Lambda表达式创建线程 —”);
// 使用Lambda表达式简化Runnable接口的实现
Thread lambdaThread = new Thread(() -> {
// 循环执行3次
for (int i = 1; i <= 3; i++) {
// 获取当前线程名称并打印计数信息
System.out.println(Thread.currentThread().getName() + " - Lambda计数: " + i);
try {
// 线程休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, “Lambda线程”);// 启动线程
lambdaThread.start();
// 等待线程执行完成
try {
lambdaThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
-
演示线程同步机制
-
对比普通计数器(非线程安全)和同步计数器(线程安全)
-
通过创建多个线程同时访问共享资源,展示线程安全问题及其解决方案
*/
private static void demonstrateThreadSynchronization() {
System.out.println(“\n— 线程同步演示 —”);// 共享资源 - 创建非线程安全的计数器实例
Counter counter = new Counter();// 创建5个线程同时操作共享资源
Thread[] threads = new Thread[5];
for (int i = 0; i < threads.length; i++) {
// 每个线程执行1000次递增操作
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
}
}, “线程-” + i);
}// 启动所有线程
for (Thread thread : threads) {
thread.start();
}// 等待所有线程完成
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}// 打印最终计数,由于线程安全问题,结果可能小于5000
System.out.println("最终计数(应该有线程安全问题): " + counter.getCount());// 使用同步的计数器 - 创建线程安全的计数器实例
SynchronizedCounter syncCounter = new SynchronizedCounter();// 创建5个线程同时操作同步计数器
Thread[] syncThreads = new Thread[5];
for (int i = 0; i < syncThreads.length; i++) {
syncThreads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
syncCounter.increment();
}
}, “同步线程-” + i);
}// 启动所有线程
for (Thread thread : syncThreads) {
thread.start();
}// 等待所有线程完成
for (Thread thread : syncThreads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}// 打印同步计数器的最终计数,由于线程安全,结果应为5000
System.out.println("同步计数器最终计数: " + syncCounter.getCount());
}
/**
-
演示线程通信机制
-
使用生产者-消费者模型,基于wait/notify机制实现线程间通信
-
生产者线程生产消息,消费者线程消费消息,通过同步块确保线程安全
*/
private static void demonstrateThreadCommunication() {
System.out.println(“\n— 线程通信演示 —”);// 生产者-消费者模型 - 创建容量为3的消息队列
MessageQueue queue = new MessageQueue(3);// 生产者线程 - 生产5条消息
Thread producer = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
String message = “消息-” + i;
// 生产消息,当队列满时会阻塞等待
queue.produce(message);
System.out.println("生产: " + message);
try {
// 每生产一条消息后休眠500毫秒
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, “生产者”);// 消费者线程 - 消费5条消息
Thread consumer = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
// 消费消息,当队列空时会阻塞等待
String message = queue.consume();
System.out.println("消费: " + message);
try {
// 每消费一条消息后休眠800毫秒(消费速度慢于生产速度)
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, “消费者”);// 启动生产者和消费者线程
producer.start();
consumer.start();// 等待生产者和消费者线程完成
try {
producer.join();
consumer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
-
演示线程池的使用
-
创建固定大小的线程池,提交多个任务并等待执行完成
-
展示了Executor框架的基本用法和线程池的优势
*/
private static void demonstrateThreadPool() {
System.out.println(“\n— 线程池演示 —”);// 创建固定大小的线程池 - 核心线程数为3
ExecutorService executor = Executors.newFixedThreadPool(3);// 提交5个任务到线程池
for (int i = 1; i <= 5; i++) {
// 使用final变量保存任务ID,以便在Lambda表达式中使用
final int taskId = i;
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
try {
// 模拟任务执行耗时1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 完成任务 " + taskId);
});
}// 关闭线程池 - 不再接受新任务,但会等待已提交任务完成
executor.shutdown();try {
// 等待所有任务完成,设置超时时间为10秒
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
// 超时后强制关闭线程池
executor.shutdownNow();
}
} catch (InterruptedException e) {
// 捕获中断异常,强制关闭线程池
executor.shutdownNow();
}// 打印线程池任务完成信息
System.out.println(“线程池任务全部完成”);
}
/**
-
演示并发工具的使用
-
- 使用AtomicInteger进行无锁编程
-
- 使用ReentrantLock进行显式锁控制
-
展示了Java并发包提供的高级并发工具
*/
private static void demonstrateConcurrencyTools() {
System.out.println(“\n— 并发工具演示 —”);// 使用Atomic类(无锁编程) - 创建原子计数器实例
AtomicCounter atomicCounter = new AtomicCounter();// 创建5个线程同时操作原子计数器
Thread[] atomicThreads = new Thread[5];
for (int i = 0; i < atomicThreads.length; i++) {
atomicThreads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
atomicCounter.increment();
}
}, “原子线程-” + i);
}// 启动所有线程
for (Thread thread : atomicThreads) {
thread.start();
}// 等待所有线程完成
for (Thread thread : atomicThreads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}// 打印原子计数器的最终计数,结果应为5000
System.out.println("原子计数器最终计数: " + atomicCounter.getCount());// 使用Lock接口 - 演示显式锁的使用
System.out.println(“\n— Lock接口演示 —”);
LockCounter lockCounter = new LockCounter();// 创建2个线程同时操作Lock计数器
Thread lockThread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
lockCounter.increment();
}
}, “Lock线程1”);Thread lockThread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
lockCounter.increment();
}
}, “Lock线程2”);// 启动线程
lockThread1.start();
lockThread2.start();// 等待线程完成
try {
lockThread1.join();
lockThread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}// 打印Lock计数器的最终计数,结果应为2000
System.out.println("Lock计数器最终计数: " + lockCounter.getCount());
}
}
- 线程生命周期:新建、就绪、运行、阻塞、死亡
/**
-
自定义线程类 - 通过继承Thread类创建线程
-
用于演示线程创建的第一种方式:继承Thread类并重写run方法
*/
class MyThread extends Thread {
// 线程名称字段
private String threadName;/**
- 构造函数,设置线程名称
- @param name 线程名称
*/
public MyThread(String name) {
this.threadName = name;
}
/**
- 线程执行的核心方法,重写父类Thread的run方法
- 执行循环打印计数信息,并在每次循环后休眠100毫秒
*/
@Override
public void run() {
// 循环执行3次
for (int i = 1; i <= 3; i++) {
// 打印线程名称和当前计数值
System.out.println(threadName + " 运行中… 计数: " + i);
try {
// 线程休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
// 捕获中断异常并打印信息
System.out.println(threadName + " 被中断");
}
}
// 打印线程执行完成信息
System.out.println(threadName + " 执行完成");
}
}
/**
-
自定义Runnable实现类
-
用于演示线程创建的第二种方式:实现Runnable接口
*/
class MyRunnable implements Runnable {
// 任务名称字段
private String taskName;/**
- 构造函数,设置任务名称
- @param name 任务名称
*/
public MyRunnable(String name) {
this.taskName = name;
}
/**
- 任务执行的核心方法,实现Runnable接口的run方法
- 执行循环打印步骤信息,并在每次循环后休眠150毫秒
*/
@Override
public void run() {
// 循环执行3次
for (int i = 1; i <= 3; i++) {
// 打印任务名称和当前步骤
System.out.println(taskName + " 执行中… 步骤: " + i);
try {
// 线程休眠150毫秒
Thread.sleep(150);
} catch (InterruptedException e) {
// 捕获中断异常并打印信息
System.out.println(taskName + " 被中断");
}
}
// 打印任务执行完成信息
System.out.println(taskName + " 执行完成");
}
}
/**
-
普通计数器(存在线程安全问题)
-
用于演示非线程安全的计数器在多线程环境下的问题
*/
class Counter {
// 计数字段
private int count = 0;/**
- 计数器递增方法
- 非原子操作,在多线程环境下可能导致计数不准确
- 非线程安全
*/
public void increment() {
// 非原子操作,包含读取、修改、写入三个步骤
count++; // 非原子操作,存在线程安全问题
}
/**
- 获取当前计数值
- @return 当前计数值
*/
public int getCount() {
// 返回当前计数值
return count;
}
}
/**
-
同步计数器(线程安全)
-
使用synchronized关键字保证线程安全
*/
class SynchronizedCounter {
// 计数字段
private int count = 0;/**
- 同步递增方法
- 使用synchronized关键字确保多线程环境下的原子性
- 线程安全
*/
public synchronized void increment() {
// 使用synchronized关键字保证原子操作
count++;
}
/**
- 同步获取计数值方法
- 使用synchronized关键字确保多线程环境下的可见性
- @return 当前计数值
*/
public synchronized int getCount() {
// 使用synchronized关键字保证可见性
return count;
}
}
/**
-
消息队列(生产者-消费者模型)
-
实现了基于wait/notify机制的线程通信
*/
class MessageQueue {
private final String[] messages; // 存储消息的数组
private int count = 0; // 当前消息数量
private int putIndex = 0; // 下一个消息放入的索引
private int takeIndex = 0; // 下一个消息取出的索引/**
- 构造函数,设置队列容量
- @param capacity 队列最大容量
*/
public MessageQueue(int capacity) {
// 初始化消息存储数组
messages = new String[capacity];
}
/**
-
生产消息方法
-
当队列满时等待,生产消息后通知消费者
-
@param message 要生产的消息
*/
public synchronized void produce(String message) {
// 使用while循环检查条件,防止虚假唤醒
while (count == messages.length) {
try {
// 队列满,等待消费者消费
wait();
} catch (InterruptedException e) {
// 打印异常堆栈信息
e.printStackTrace();
}
}// 将消息放入队列
messages[putIndex] = message;
// 更新下一个消息放入的索引,循环使用数组空间
putIndex = (putIndex + 1) % messages.length; // 循环使用数组空间
// 增加消息计数
count++;
// 通知所有等待的消费者线程
notifyAll(); // 通知消费者可以消费了
}
/**
-
消费消息方法
-
当队列空时等待,消费消息后通知生产者
-
@return 消费的消息
*/
public synchronized String consume() {
// 使用while循环检查条件,防止虚假唤醒
while (count == 0) {
try {
// 队列空,等待生产者生产
wait(); // 队列空,等待生产者生产
} catch (InterruptedException e) {
// 打印异常堆栈信息
e.printStackTrace();
}
}// 从队列中取出消息
String message = messages[takeIndex];
// 更新下一个消息取出的索引,循环使用数组空间
takeIndex = (takeIndex + 1) % messages.length; // 循环使用数组空间
// 减少消息计数
count–;
// 通知所有等待的生产者线程
notifyAll(); // 通知生产者可以生产了
// 返回消费的消息
return message;
}
}
/**
-
原子计数器(使用AtomicInteger)
-
基于CAS(Compare-And-Swap)操作实现线程安全的计数
*/
class AtomicCounter {
// 使用AtomicInteger实现原子计数
private AtomicInteger count = new AtomicInteger(0);/**
- 原子递增方法
- 使用AtomicInteger的原子操作确保线程安全
- 无锁实现,性能优于synchronized
*/
public void increment() {
// 原子递增操作,基于CAS机制实现
count.incrementAndGet(); // 原子操作
}
/**
- 获取当前计数值
- @return 当前计数值
*/
public int getCount() {
// 获取当前计数值
return count.get();
}
}
/**
-
使用Lock接口的计数器
-
演示显式锁的使用方式
*/
class LockCounter {
// 计数字段
private int count = 0;
// 创建可重入锁实例
private Lock lock = new ReentrantLock(); // 可重入锁/**
- 使用显式锁的递增方法
- 获取锁后执行递增操作,在finally块中确保锁的释放
*/
public void increment() {
// 获取锁
lock.lock(); // 获取锁
try {
// 执行递增操作
count++;
} finally {
// 确保锁的释放,防止死锁
lock.unlock(); // 释放锁(确保在finally块中释放)
}
}
/**
- 使用显式锁获取计数值
- 获取锁后读取计数值,在finally块中确保锁的释放
- @return 当前计数值
*/
public int getCount() {
// 获取锁
lock.lock();
try {
// 返回当前计数值
return count;
} finally {
// 确保锁的释放
lock.unlock();
}
}
}

被折叠的 条评论
为什么被折叠?



