# Java多线程编程的实践与优化

## 线程创建与管理

### 线程创建方式

Java中创建线程主要有三种方式:继承Thread类、实现Runnable接口、实现Callable接口。推荐使用实现Runnable接口的方式,因为Java不支持多继承,使用接口可以保持类的继承体系完整性。

```java

// 实现Runnable接口

public class MyRunnable implements Runnable {

@Override

public void run() {

// 线程执行逻辑

}

}

// 使用线程池执行

ExecutorService executor = Executors.newFixedThreadPool(10);

executor.execute(new MyRunnable());

```

### 线程池优化

合理使用线程池是优化多线程性能的关键。Java提供了Executors工具类创建不同类型的线程池:

```java

// 固定大小线程池

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

// 缓存线程池

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

// 定时任务线程池

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

```

对于需要更精细控制的场景,建议直接使用ThreadPoolExecutor:

```java

ThreadPoolExecutor executor = new ThreadPoolExecutor(

corePoolSize, // 核心线程数

maximumPoolSize, // 最大线程数

keepAliveTime, // 空闲线程存活时间

TimeUnit.MILLISECONDS, // 时间单位

new LinkedBlockingQueue() // 工作队列

);

```

## 线程同步与通信

### synchronized关键字

synchronized是Java中最基本的同步机制,可以用于方法或代码块:

```java

public class SynchronizedCounter {

private int count = 0;

// 同步方法

public synchronized void increment() {

count++;

}

// 同步代码块

public void decrement() {

synchronized(this) {

count--;

}

}

}

```

### Lock接口

Java.util.concurrent.locks包提供了更灵活的锁机制:

```java

public class LockCounter {

private final ReentrantLock lock = new ReentrantLock();

private int count = 0;

public void increment() {

lock.lock();

try {

count++;

} finally {

lock.unlock();

}

}

}

```

### volatile关键字

volatile保证变量的可见性,但不保证原子性:

```java

public class VolatileExample {

private volatile boolean flag = false;

public void setFlag() {

flag = true; // 对其他线程立即可见

}

}

```

## 并发集合类

Java提供了线程安全的并发集合类,比使用synchronized包装的集合性能更好:

```java

// 并发Map

ConcurrentHashMap concurrentMap = new ConcurrentHashMap<>();

// 阻塞队列

BlockingQueue blockingQueue = new LinkedBlockingQueue<>();

// 并发List

CopyOnWriteArrayList copyOnWriteList = new CopyOnWriteArrayList<>();

```

## 原子操作类

java.util.concurrent.atomic包提供了原子操作类,无需使用锁即可实现线程安全:

```java

public class AtomicCounter {

private AtomicInteger count = new AtomicInteger(0);

public void increment() {

count.incrementAndGet(); // 原子操作

}

public int getCount() {

return count.get();

}

}

```

## 线程间通信

### wait/notify机制

传统的线程间通信方式:

```java

public class WaitNotifyExample {

private final Object lock = new Object();

private boolean condition = false;

public void waitForCondition() throws InterruptedException {

synchronized(lock) {

while (!condition) {

lock.wait(); // 释放锁并等待

}

// 条件满足后的处理

}

}

public void setCondition() {

synchronized(lock) {

condition = true;

lock.notifyAll(); // 通知所有等待线程

}

}

}

```

### Condition接口

更灵活的线程通信机制:

```java

public class ConditionExample {

private final Lock lock = new ReentrantLock();

private final Condition condition = lock.newCondition();

private boolean ready = false;

public void await() throws InterruptedException {

lock.lock();

try {

while (!ready) {

condition.await();

}

} finally {

lock.unlock();

}

}

public void signal() {

lock.lock();

try {

ready = true;

condition.signalAll();

} finally {

lock.unlock();

}

}

}

```

## 性能优化实践

### 减少锁竞争

1. 锁细化:将大锁拆分为多个小锁

2. 锁粗化:在适当情况下合并多个小锁

3. 使用读写锁:ReadWriteLock适用于读多写少的场景

```java

public class ReadWriteLockExample {

private final ReadWriteLock lock = new ReentrantReadWriteLock();

private final Lock readLock = lock.readLock();

private final Lock writeLock = lock.writeLock();

private Map data = new HashMap<>();

public String get(String key) {

readLock.lock();

try {

return data.get(key);

} finally {

readLock.unlock();

}

}

public void put(String key, String value) {

writeLock.lock();

try {

data.put(key, value);

} finally {

writeLock.unlock();

}

}

}

```

### 避免死锁

1. 按固定顺序获取锁

2. 使用tryLock()设置超时时间

3. 使用死锁检测工具

```java

public class DeadlockAvoidance {

private final Lock lock1 = new ReentrantLock();

private final Lock lock2 = new ReentrantLock();

public void method1() {

lock1.lock();

try {

// 一些操作

if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) {

try {

// 成功获取lock2

} finally {

lock2.unlock();

}

}

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

} finally {

lock1.unlock();

}

}

}

```

### 使用无锁编程

在某些场景下,可以使用无锁数据结构:

```java

public class LockFreeStack {

private AtomicReference> top = new AtomicReference<>();

public void push(E item) {

Node newHead = new Node<>(item);

Node oldHead;

do {

oldHead = top.get();

newHead.next = oldHead;

} while (!top.compareAndSet(oldHead, newHead));

}

private static class Node {

final E item;

Node next;

Node(E item) {

this.item = item;

}

}

}

```

## 最佳实践总结

1. 优先使用高级并发工具:如并发集合、原子变量等

2. 合理使用线程池:避免频繁创建和销毁线程

3. 最小化同步范围:只在必要的时候进行同步

4. 优先使用不可变对象:避免同步开销

5. 注意资源清理:确保线程池正确关闭

6. 合理设置线程优先级:避免线程饥饿

7. 使用线程安全的单例模式:

```java

public class Singleton {

private static volatile Singleton instance;

private Singleton() {}

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

```

通过合理运用这些多线程编程技术和优化策略,可以显著提升Java应用程序的性能和稳定性,同时降低并发编程的复杂度。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐