并发与并行编程实践
发布时间: 2024-02-01 01:48:39 阅读量: 34 订阅数: 34
# 1. 介绍
## 1.1 什么是并发编程
并发编程是指程序设计中涉及多个同时活动的组件,这些组件可能在某些时间上重叠执行,但并不是同时执行。在并发编程中,通常会涉及到多线程、协程、事件驱动等机制,旨在最大限度地提高计算机系统的利用率和吞吐量。
## 1.2 什么是并行编程
与并发编程相反,并行编程是指真正意义上的同时执行多个任务。在并行编程中,各个任务之间是独立的,彼此不会干扰,任务间可以同时进行,这通常需要多核或多处理器系统的支持。
## 1.3 并发与并行的区别与联系
并发与并行都涉及多个任务同时执行,不同之处在于并发是逻辑上的同时执行,而并行是物理上的同时执行。并发更关注任务之间的调度和交替执行,而并行更侧重任务之间的独立执行。然而,并发与并行并不是相互排斥的,它们往往会结合在一起,共同应用于实际的软件系统中。
# 2. 并发编程基础
并发编程是指程序设计中涉及多个同时运行的计算任务,这些任务并不是同时执行的,而是通过时间片轮转的方式实现看似同时运行的效果。在并发编程中,最基本的单位是线程,线程是操作系统能够进行运算调度的最小单位。
#### 2.1 线程概念与创建
在并发编程中,线程是指在同一时间段内能够运行的一段程序,它是进程的子任务。线程可以并发执行,因此它是实现并发编程的基本单元。在Java中,创建线程的方式有两种,一种是继承Thread类,另一种是实现Runnable接口,并将其传递给Thread类的构造函数。
```java
// 通过继承Thread类创建线程
class MyThread extends Thread {
public void run() {
System.out.println("This is a thread created by extending Thread class.");
}
}
// 通过实现Runnable接口创建线程
class MyRunnable implements Runnable {
public void run() {
System.out.println("This is a thread created by implementing Runnable interface.");
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new MyThread();
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}
```
通过上面的代码示例可知,通过继承Thread类和实现Runnable接口都可以实现线程的创建。
#### 2.2 锁与同步
在多线程并发执行的情况下,可能会出现多个线程访问共享资源的问题,这时就需要使用锁和同步机制来保证线程安全。在Java中,可以使用synchronized关键字或者Lock接口来实现同步。
```java
// 使用synchronized关键字实现同步
public synchronized void synchronizedMethod() {
// 同步代码块
synchronized (this) {
// 需要同步的代码
}
}
// 使用Lock接口实现同步
Lock lock = new ReentrantLock();
public void synchronizedMethod() {
lock.lock();
try {
// 需要同步的代码
} finally {
lock.unlock();
}
}
```
#### 2.3 线程间通信
当多个线程之间需要进行数据交换或者协作时,就需要线程间通信。在Java中,可以使用wait()、notify()和notifyAll()方法实现线程间通信。
```java
public class SharedObject {
private boolean isReady = false;
public synchronized void doWork() {
while (!isReady) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 执行任务
}
public synchronized void finishWork() {
// 完成任务
isReady = true;
notifyAll();
}
}
```
在上面的示例中,doWork()方法会通过wait()方法释放锁并等待,直到finishWork()方法调用notifyAll()唤醒它。
#### 2.4 线程安全与可见性问题
并发编程中常常会遇到线程安全与可见性问题,比如不当的共享资源访问可能导致数据不一致,以及一个线程对共享变量的修改在另一个线程中不可见。针对这些问题,需要使用volatile关键字、原子变量或者使用synchronized关键字等方式来解决。
以上便是并发编程基础的内容,通过对线程的概念与创建、锁与同步、线程间通信、线程安全与可见性问题的介绍,有助于理解并发编程的基本概念和技术。
# 3. 并发编程高级技术
在并发编程的高级技术中,我们将深入探讨一些更加复杂和关键的概念和工具,以提高并发编程的效率和性能。
#### 3.1 线程池
线程池是一种管理和复用线程的技术,通过线程池可以减少线程创建和销毁的消耗,提高系统的性能和稳定性。在Java中,可以使用`ThreadPoolExecutor`来创建和管理线程池,设置核心线程数、最大线程数、线程存活时间等参数,以适应不同的并发场景。
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池
for (int i = 0; i < 10; i++) {
final int task = i;
threadPool.execute(() -> {
System.out.println("Task " + task + " is running.");
});
}
threadPool.shutdown(); // 关闭线程池
}
}
```
上面的代码展示了如何使用Java的线程池来执行多个任务,线程池会复用线程来执行任务,提高了效率。
#### 3.2 信号量与并发容器
在并发编程中,信号量和并发容器是常用的工具,用于控制对共享资源的访问和操作。在Java中可以使用`Semaphore`来实现信号量控制,使用`ConcurrentHashMap`等并发容器来实现线程安全的数据操作。
```java
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 创建一个信号量,允许两个线程同时访问
Runnable task = () -> {
try {
semaphore.acquire(); // 获取许可
System.out.println("Thread " + Thread.currentThread().getId() + " is accessing the resource.");
Thread.sleep(2000); // 模拟操作耗时
semaphore.release(); // 释放许可
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 5; i++) {
new Thread(task).star
```
0
0