Java 线程并发实战指南:使用方法与常见坑点
Java 并发编程实战指南
Java 并发编程实战指南
文章主题:Java 并发编程实战
目标读者:Java 开发者
内容特点:实战教程、代码示例、最佳实践
引言
在 Java 开发中,多线程编程是提升应用性能的关键技术。然而,并发编程也带来了许多挑战,如线程安全问题、死锁、内存可见性等。本文将深入讲解 Java 线程并发的常用方法、最佳实践以及常见坑点。
一、Java 线程创建方式
1. 继承 Thread 类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
// 启动线程
MyThread thread = new MyThread();
thread.start();
2. 实现 Runnable 接口
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running: " + Thread.currentThread().getName());
}
}
// 启动线程
Thread thread = new Thread(new MyRunnable());
thread.start();
3. 实现 Callable 接口(带返回值)
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable {
@Override
public String call() throws Exception {
return "Result from Callable";
}
}
// 启动线程
FutureTask futureTask = new FutureTask(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start();
String result = futureTask.get(); // 获取返回值
4. 使用线程池
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交任务
executor.submit(() -> {
System.out.println("Task executed in thread: " + Thread.currentThread().getName());
});
// 关闭线程池
executor.shutdown();
二、并发工具类
1. CountDownLatch(倒计时门闩)
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
// 启动 3 个线程
for (int i = 0; i {
System.out.println("Task " + Thread.currentThread().getName() + " completed");
latch.countDown();
}).start();
}
// 等待所有任务完成
latch.await();
System.out.println("All tasks completed");
}
}
2. CyclicBarrier(循环屏障)
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("All threads reached barrier");
});
for (int i = 0; i {
System.out.println("Thread " + Thread.currentThread().getName() + " working");
try {
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
3. Semaphore(信号量)
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 允许 3 个线程同时访问
for (int i = 0; i {
try {
semaphore.acquire();
System.out.println("Thread " + Thread.currentThread().getName() + " accessing resource");
Thread.sleep(1000);
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
4. ReentrantLock(可重入锁)
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
}
三、常见坑点与解决方案
1. 线程安全问题
问题:多个线程同时修改共享变量导致数据不一致
解决方案:
- 使用 volatile 关键字保证可见性
- 使用 synchronized 关键字保证原子性
- 使用 ConcurrentHashMap 替代 HashMap
- 使用原子类(AtomicInteger、AtomicLong 等)
2. 死锁问题
问题:两个或多个线程互相等待对方释放锁
解决方案:
- 避免嵌套锁
- 使用 tryLock() 和超时机制
- 按固定顺序获取锁
3. 内存可见性问题
问题:一个线程修改了变量,其他线程看不到修改
解决方案:
- 使用 volatile 关键字
- 使用 synchronized 或 ReentrantLock
- 使用 ThreadLocal 隔离线程状态
4. 线程池配置不当
问题:线程池过大导致内存溢出,过小导致性能问题
最佳实践:
// CPU 密集型任务
int cpuCount = Runtime.getRuntime().availableProcessors();
ExecutorService cpuExecutor = Executors.newFixedThreadPool(cpuCount + 1);
// IO 密集型任务
int ioThreads = cpuCount * 2;
ExecutorService ioExecutor = Executors.newFixedThreadPool(ioThreads);
四、最佳实践
- 优先使用线程池:避免频繁创建和销毁线程
- 使用不可变对象:减少线程同步需求
- 合理设计锁粒度:避免锁竞争
- 使用并发容器:如 ConcurrentHashMap、BlockingQueue 等
- 避免在锁中执行耗时操作:提高并发性能
- 使用 CompletableFuture 进行异步编程:简化异步代码
五、总结
Java 并发编程是提升应用性能的关键技术。掌握线程创建方式、并发工具类和常见坑点的解决方案,可以帮助开发者写出高效、安全的并发代码。在实际开发中,应遵循最佳实践,合理使用并发工具,避免常见的并发陷阱。
—
#Java 并发 #多线程 #Java 开发 #性能优化 #技术教程



发表评论