第1课java_并发基础
热度🔥:39 免费课程
授课语音
Java并发编程介绍
1. 介绍
在实际开发中,Java的并发编程被广泛应用,它能够有效地利用系统资源,提升程序的性能和响应能力。并发可以通过多线程、多进程、协程和异步编程等方式实现。
进程与线程
进程:进程是操作系统中正在运行的程序实例。每个进程有独立的地址空间和系统资源。
- 进程间通信(IPC)相对复杂,通常使用管道、消息队列和共享内存等机制。
- 进程切换和资源使用的开销较大,但一个进程的崩溃不会影响其他进程。
- 适用于独立应用程序,比如浏览器和文本编辑器。
线程:线程是进程中的执行单元。
- 一个进程可以包含多个线程,这些线程共享进程的地址空间和资源。
- 线程间通信相对简单,切换和资源使用开销较小,但仍然涉及内核态的上下文切换。
- 适用于处理并发任务。
并发与并行
- 并发:多个线程或任务在同一时间段内交替执行。
- 并行:多个线程或任务在同一时刻同时执行,这需要硬件的支持,如多核处理器。
生命周期
进程的生命周期包括:
- 新建(操作系统分配资源并初始化)、
- 就绪(等待操作系统调度)、
- 运行(CPU上执行指令)、
- 阻塞(等待某些事件完成)、
- 结束(执行完毕或由于错误终止)。
进程管理包括:
- 创建(例如使用
fork
)、 - 调度(操作系统调度算法,比如轮询和优先级调度)、
- 通信(管道、消息队列、共享内存、信号量等)、
- 终止(操作系统释放并清理资源)。
线程的生命周期包括:
- 新建(线程被创建但未执行)、
- 就绪(等待操作系统调度)、
- 运行(CPU上执行指令)、
- 阻塞(等待同步锁或其他资源)、
- 等待(通过
wait
进入等待状态)、 - 死亡(线程执行完成或因异常终止)。
线程管理包括:
- 创建(继承
Thread
类或实现Runnable
接口)、 - 调度(JVM和操作系统结合管理)、
- 同步(使用
synchronized
等机制协调对共享资源的访问)、 - 线程池(提供高效复用线程和任务调度机制)。
图示
线程创建方式
- 继承
Thread
类:适合简单场景,但Java是单继承的,限制了不能继承其他类。 - 实现
Runnable
接口:更加灵活,避免了Java的单继承限制,实际开发中推荐使用这种方式。
2. 代码案例
进程代码案例
package com.zhilitech;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ProcessDemo {
public static void main(String[] args) {
try {
// 创建并启动一个进程,该进程尝试运行一个不存在的程序,以模拟异常
ProcessBuilder processBuilder = new ProcessBuilder("java", "NonExistentProgram");
Process process = processBuilder.start();
// 读取进程的错误流,获取异常信息
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = errorReader.readLine()) != null) {
System.err.println("进程错误: " + line); // 输出进程的错误信息
}
// 等待进程结束,并获取退出码
int exitCode = process.waitFor();
System.out.println("进程结束,退出码: " + exitCode);
/*
* 输出示例:
* 进程错误: 错误: 找不到或无法加载主类 NonExistentProgram
* 进程错误: 原因: java.lang.ClassNotFoundException: NonExistentProgram
* 进程结束,退出码: 1
*/
} catch (IOException e) {
// 捕获并处理输入输出异常
System.err.println("IO 异常发生: " + e.getMessage());
} catch (InterruptedException e) {
// 捕获并处理进程等待被中断的异常
System.err.println("进程被中断: " + e.getMessage());
} catch (Exception e) {
// 捕获其他异常
System.err.println("发生异常: " + e.getMessage());
}
}
}
线程代码案例
package com.zhilitech;
import java.util.concurrent.*;
// 共享数据类,用于线程间的同步和通信
class SharedData {
private String data;
// volatile修饰符确保变量的可见性,防止指令重排序,但不能保证原子性,适用于简单的同步场景
private volatile boolean available = false;
// 生产者线程调用的方法
public synchronized void produce(String data) throws InterruptedException {
while (available) {
wait(); // 阻塞,直到数据被消费
}
this.data = data; // 设置共享数据
available = true; // 标记数据可用
notify(); // 通知消费者线程
}
// 消费者线程调用的方法
public synchronized String consume() throws InterruptedException {
while (!available) {
wait(); // 阻塞,直到数据被生产
}
available = false; // 标记数据已消费
notify(); // 通知生产者线程
return data; // 返回消费的数据
}
}
// 继承 Thread 类创建生产者线程
class ProducerThread extends Thread {
private SharedData sharedData;
public ProducerThread(SharedData sharedData) {
this.sharedData = sharedData;
}
@Override
public void run() {
String[] dataToProduce = {"数据1", "数据2", "数据3"};
try {
for (String data : dataToProduce) {
System.out.println("生产者线程" + Thread.currentThread().getName() + " 生产了: " + data);
sharedData.produce(data); // 生产数据
Thread.sleep(100); // 模拟生产时间
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 继承 Thread 类创建消费者线程
class ConsumerThread extends Thread {
private SharedData sharedData;
public ConsumerThread(SharedData sharedData) {
this.sharedData = sharedData;
}
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
String data = sharedData.consume(); // 消费数据
System.out.println("消费者线程" + Thread.currentThread().getName() + " 消费了: " + data);
Thread.sleep(200); // 模拟消费时间
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 实现 Runnable 接口创建生产者线程
class ProducerRunnable implements Runnable {
private SharedData sharedData;
private String[] dataToProduce;
public ProducerRunnable(SharedData sharedData, String... dataToProduce) {
this.sharedData = sharedData;
this.dataToProduce = dataToProduce;
}
@Override
public void run() {
try {
for (String data : dataToProduce) {
System.out.println("生成者线程" + Thread.currentThread().getName() + " 生产了: " + data);
sharedData.produce(data); // 生产数据
Thread.sleep(100); // 模拟生产时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 设置中断状态
e.printStackTrace();
}
}
}
// 实现 Runnable 接口创建消费者线程
class ConsumerRunnable implements Runnable {
private SharedData sharedData;
public ConsumerRunnable(SharedData sharedData) {
this.sharedData = sharedData;
}
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
String data = sharedData.consume(); // 消费数据
System.out.println("消费者线程" + Thread.currentThread().getName() + " 消费了: " + data);
Thread.sleep(200); // 模拟消费时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 设置中断状态
e.printStackTrace();
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// 创建共享数据对象,用于线程间的同步和通信
SharedData sharedData = new SharedData();
// 方法一:继承 Thread 类创建线程
Thread producerThread1 = new ProducerThread(sharedData);
Thread consumerThread1 = new ConsumerThread(sharedData
);
// 启动线程
producerThread1.start();
consumerThread1.start();
// 方法二:实现 Runnable 接口创建线程
Thread producerThread2 = new Thread(new ProducerRunnable(sharedData, "数据4", "数据5", "数据6"));
Thread consumerThread2 = new Thread(new ConsumerRunnable(sharedData));
// 启动线程
producerThread2.start();
consumerThread2.start();
try {
// 等待线程结束
producerThread1.join();
consumerThread1.join();
producerThread2.join();
consumerThread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开始线程池的测试");
// 自定义线程池
int poolSize = 4; // 线程池大小
ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
// 提交任务到线程池
executorService.submit(new ProducerRunnable(sharedData, "数据1", "数据2", "数据3"));
executorService.submit(new ConsumerRunnable(sharedData));
executorService.submit(new ProducerRunnable(sharedData, "数据4", "数据5", "数据6"));
executorService.submit(new ConsumerRunnable(sharedData));
// 关闭线程池
executorService.shutdown();
try {
// 等待线程池中所有任务完成
if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
executorService.shutdownNow(); // 超时则强制关闭
}
} catch (InterruptedException e) {
executorService.shutdownNow(); // 线程被中断时强制关闭
Thread.currentThread().interrupt(); // 恢复中断状态
}
/*
* 示例输出:
* 生成者线程Thread-2 生产了: 数据4
* 生产者线程Thread-0 生产了: 数据1
* 消费者线程Thread-1 消费了: 数据4
* 消费者线程Thread-3 消费了: 数据1
* 生产者线程Thread-0 生产了: 数据2
* 生成者线程Thread-2 生产了: 数据5
* 消费者线程Thread-1 消费了: 数据2
* 消费者线程Thread-3 消费了: 数据5
* 生产者线程Thread-0 生产了: 数据3
* 生成者线程Thread-2 生产了: 数据6
* 消费者线程Thread-1 消费了: 数据3
* 消费者线程Thread-3 消费了: 数据6
* 开始线程池的测试
* 生成者线程pool-1-thread-1 生产了: 数据1
* 生成者线程pool-1-thread-3 生产了: 数据4
* 消费者线程pool-1-thread-2 消费了: 数据1
* 消费者线程pool-1-thread-4 消费了: 数据4
* 生成者线程pool-1-thread-3 生产了: 数据5
* 生成者线程pool-1-thread-1 生产了: 数据2
* 消费者线程pool-1-thread-2 消费了: 数据5
* 消费者线程pool-1-thread-4 消费了: 数据2
* 生成者线程pool-1-thread-3 生产了: 数据6
* 生成者线程pool-1-thread-1 生产了: 数据3
* 消费者线程pool-1-thread-2 消费了: 数据6
* 消费者线程pool-1-thread-4 消费了: 数据3
*/
}
}