Java并发编程实战指南
立即解锁
发布时间: 2025-08-18 02:24:33 阅读量: 2 订阅数: 14 

### Java并发编程实战指南
#### 1. 并发操作中的锁保护
在并发编程中,涉及到对一个或两个集合的操作时,需要使用相同的锁进行保护。依赖一个集合的结果来查询另一个集合的操作,需要原子性地执行,即这些操作要作为一个整体,在操作完成之前,任何一个集合都不能发生改变。
#### 2. 将工作拆分为独立线程
##### 2.1 问题描述
当有可以拆分为独立线程的工作,并且希望最大化利用可用的CPU资源时,该如何处理?
##### 2.2 解决方案
可以使用`ThreadPoolExecutor`实例,它能将任务拆分为离散的单元。以下是示例代码:
```java
private void start() throws InterruptedException {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
for (int i = 0; i < 10; i++) {
final int localI = i;
queue.add(new Runnable() {
public void run() {
doExpensiveOperation(localI);
}
});
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1000,
TimeUnit.MILLISECONDS, queue);
executor.prestartAllCoreThreads();
executor.shutdown();
executor.awaitTermination(100000, TimeUnit.SECONDS);
System.out.println("Look ma! all operations were completed");
}
```
##### 2.3 工作原理
`ThreadPoolExecutor`由两个组件组成:待执行任务的队列和执行器,执行器负责告知如何执行任务。队列中填充的是`Runnable`对象,其`run()`方法包含了要执行的代码。
`ThreadPoolExecutor`使用的队列是`BlockingQueue`接口的实现。`BlockingQueue`接口表示,如果队列中没有元素,队列的消费者会等待(被挂起)。这对于`ThreadPoolExecutor`的高效工作是必要的。
具体步骤如下:
1. 调用队列的`add()`方法,将需要并行执行的任务填充到队列中。
2. 初始化执行器。
`ThreadPoolExecutor`的构造函数有多个参数,以下是各参数的说明:
| 参数 | 描述 |
| ---- | ---- |
| CorePoolSize | 提交任务时创建的最小线程数 |
| MaximumPoolSize | 执行器可创建的最大线程数 |
| KeepAliveTime | 等待线程在被处理之前等待工作的时间(只要活动线程数仍大于`CorePoolSize`) |
| TimeUnit | `KeepAliveTime`的时间单位(如`TimeUnit.SECONDS`、`TimeUnit.MILLISECONDS`) |
| WorkQueue | 包含执行器要处理任务的阻塞队列 |
初始化`ThreadPoolExecutor`后,调用`prestartAllCoreThreads()`方法,该方法会创建`CorePoolSize`指定数量的线程,“预热”`ThreadPoolExecutor`,如果队列不为空,会主动开始从队列中消费任务。
要等待所有任务完成,可以调用`ThreadPoolExecutor`的`shutdown()`方法,该方法会指示执行器不再接受队列中的新事件(之前提交的事件会完成处理)。然后调用`awaitTermination()`方法,使主线程等待,直到`ThreadPoolExecutor`队列中的所有`Runnable`对象执行完毕。
##### 2.4 线程数量配置
`ThreadPoolExecutor`需要正确配置以最大化CPU使用率。执行器的最佳线程数取决于提交的任务类型。如果任务是CPU密集型的,使用与当前核心数相同的执行器是理想的;如果任务是I/O密集型的,执行器应拥有比当前核心数更多的线程。I/O操作越密集,线程数量应越多。
#### 3. 线程协调
##### 3.1 问题描述
当应用程序需要两个或多个线程协同工作时,该如何实现?
##### 3.2 解决方案
以下提供了三种解决方案:
**方案一:使用`wait/notify`进行线程同步**
```java
private final Object objectToSync = new Object();
private void start() {
loadItems();
Thread inventoryThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Inventory from Database...");
loadInventory();
synchronized (objectToSync) {
objectToSync.notify();
}
}
});
synchronized (objectToSync) {
inventoryThread.start();
try {
objectToSync.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread ordersThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Orders from XML Web service...");
loadOrders();
synchronized (objectToSync) {
objectToSync.notify();
}
}
});
synchronized (objectToSync) {
ordersThread.start();
try {
objectToSync.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
processOrders();
}
```
在这个方案中,主线程等待`objectToSync`对象,直到数据库加载线程完成。数据库加载线程完成后,会通知`objectToSync`,表示等待该对象的线程可以继续执行。加载订单时也采用相同的过程。确保库存和订单都加载完成后,主线程执行`processOrder()`方法处理所有订单。
**方案二:使用`CountDownLatch`**
```java
CountDownLatch latch = new CountDownLatch(2);
private void start() {
loadItems();
Thread inventoryThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Inventory from Database...");
loadInventory();
latch.countDown();
}
});
inventoryThread.start();
Thread ordersThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Orders from XML Web service...");
loadOrders();
latch.countDown();
}
});
ordersThread.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
processOrders();
}
```
创建一个初始值为2的`CountDownLatch`对象。当两个线程(库存加载线程和订单信息加载线程)完成执行时,它们会调用`CountDownLatch`的`countDown()`方法,将计数器的值减1。主线程会等待,直到`CountDownLatch`的值达到0,然后继续执行。
**方案三:使用`Thread.join()`**
```java
private void start() {
loadItems();
Thread inventoryThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Inventory from Database...");
loadInventory();
}
});
inventoryThread.start();
try {
inventoryThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread ordersThread = new Thread(new Runnable() {
public void run() {
System.out.println("Loading Orders from XML Web service...");
loadOrders();
}
});
ordersThread.start();
try {
ordersTh
```
0
0
复制全文