在开始Java并发编程之前,我们需要配置好开发环境。以下是Maven项目的基本配置:
xml复制<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
这个配置指定了Java 8的编译环境,并引入了Lombok(简化代码)和Logback(日志记录)依赖。选择Java 8是因为它提供了相对成熟的并发API,同时保持较好的兼容性。
并发编程中,良好的日志记录至关重要。以下是推荐的logback.xml配置:
xml复制<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<property name="LOG_HOME" value="/home" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
这个配置的关键点:
注意:生产环境中建议将日志级别调整为DEBUG或TRACE时谨慎,可能产生大量日志影响性能。
进程和线程是操作系统的基本概念,但在Java并发编程中需要深入理解它们的差异:
资源分配:
执行模型:
通信成本:
java复制// 线程共享内存示例
public class SharedMemoryDemo {
static int sharedCount = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sharedCount++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sharedCount++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + sharedCount); // 通常不是2000
}
}
这个例子展示了线程共享变量导致的数据竞争问题,实际输出通常小于2000,因为++操作不是原子的。
并发和并行经常被混淆,但它们有本质区别:
并发(Concurrency):
并行(Parallelism):
java复制// 并发示例:单核上的时间片轮转
public class ConcurrencyDemo {
public static void main(String[] args) {
new Thread(() -> System.out.println("Task 1")).start();
new Thread(() -> System.out.println("Task 2")).start();
}
}
// 并行示例:多核上的真正同时执行
public class ParallelismDemo {
public static void main(String[] args) {
IntStream.range(0, 10)
.parallel()
.forEach(i -> System.out.println(Thread.currentThread().getName()));
}
}
实际开发中,我们通常使用线程池来管理并发任务,合理设置线程数:
java复制public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running: " + getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 正确启动方式
// thread.run(); // 错误!这会在主线程执行
}
}
缺点:Java是单继承,这种方式限制了类的扩展性。
java复制public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running: "
+ Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
优点:
Java 8后可以用lambda简化:
java复制new Thread(() -> System.out.println("Lambda running")).start();
java复制public class CallableDemo {
public static void main(String[] args) throws Exception {
FutureTask<Integer> task = new FutureTask<>(() -> {
Thread.sleep(1000);
return 42;
});
new Thread(task).start();
System.out.println("Result: " + task.get()); // 阻塞直到获取结果
}
}
特点:
Java线程有6种状态(Thread.State):
java复制public class ThreadStateDemo {
public static void main(String[] args) throws Exception {
Thread t = new Thread(() -> {
try {
Thread.sleep(1000);
synchronized (ThreadStateDemo.class) {
ThreadStateDemo.class.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE
Thread.sleep(500);
System.out.println(t.getState()); // TIMED_WAITING
Thread.sleep(1000);
System.out.println(t.getState()); // BLOCKED (等待锁)
synchronized (ThreadStateDemo.class) {
ThreadStateDemo.class.notify();
System.out.println(t.getState()); // WAITING
}
t.join();
System.out.println(t.getState()); // TERMINATED
}
}
理解这些状态对调试多线程问题非常重要,可以用jstack工具查看线程状态。
java复制public class JoinDemo {
static int result = 0;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(1000);
result = 42;
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
t.join(); // 主线程等待t完成
System.out.println(result); // 保证输出42
}
}
注意事项:
Java没有真正的线程终止方法,interrupt()是协作式的中断机制:
java复制public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted during sleep");
Thread.currentThread().interrupt(); // 重置中断状态
}
}
System.out.println("Thread exiting");
});
t.start();
Thread.sleep(3500);
t.interrupt();
}
}
关键点:
java复制public class DaemonDemo {
public static void main(String[] args) {
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Daemon working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
daemon.setDaemon(true);
daemon.start();
System.out.println("Main thread exiting");
}
}
特点:
线程安全问题的根源在于共享数据的非原子操作:
java复制public class UnsafeCounter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
public int getCount() {
return count;
}
}
count++实际上包含三个操作:
最基本的同步机制:
java复制public class SafeCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
原理:
java复制public class SyncBlockDemo {
private final Object lock = new Object();
private int count = 0;
public void increment() {
synchronized (lock) { // 比方法级锁更灵活
count++;
}
}
}
保证可见性和有序性,但不保证原子性:
java复制public class VolatileDemo {
private volatile boolean flag = false;
public void writer() {
flag = true; // 写操作
}
public void reader() {
if (flag) { // 读操作
System.out.println("Flag is true");
}
}
}
适用场景:
java.util.concurrent.atomic包提供了原子操作类:
java复制public class AtomicDemo {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // 原子操作
}
public int getCount() {
return count.get();
}
}
实现原理:
线程创建和销毁的开销很大,线程池可以:
java复制public class ThreadPoolDemo {
public static void main(String[] args) {
int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 60L;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 0; i < 50; i++) {
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " executing");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
}
关键参数:
提供了几种常用线程池:
注意:阿里巴巴Java规范不建议直接使用Executors创建线程池,因为默认参数可能导致OOM。
允许一个或多个线程等待其他线程完成:
java复制public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executor.execute(() -> {
System.out.println("Task started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task completed");
latch.countDown();
});
}
latch.await();
System.out.println("All tasks completed");
executor.shutdown();
}
}
让一组线程到达屏障时被阻塞,直到最后一个线程到达:
java复制public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("All threads reached barrier");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("Thread waiting at barrier");
try {
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Thread continued");
}).start();
}
}
}
控制同时访问特定资源的线程数量:
java复制public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " acquired permit");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println(Thread.currentThread().getName() + " released permit");
}
}).start();
}
}
}
解决方法:
Java内存模型定义了:
重要的happens-before规则:
java复制public class HappensBeforeDemo {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42; // 1
v = true; // 2
}
public void reader() {
if (v) { // 3
System.out.println(x); // 4
}
}
}
由于volatile的happens-before规则,如果reader看到v=true,那么一定能看到x=42。
正确构造的不可变对象是线程安全的:
java复制public class FinalFieldDemo {
final int x;
public FinalFieldDemo() {
x = 42; // 正确构造
}
public void print() {
System.out.println(x); // 保证看到正确初始化的值
}
}
java复制public class RaceCondition {
private int count = 0;
public void increment() {
if (count < 10) { // 竞态条件
count++;
}
}
}
解决方法:将检查和操作作为一个原子操作
java复制public class DeadlockDemo {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// do something
}
}
}
public void method2() {
synchronized (lock2) {
synchronized (lock1) {
// do something
}
}
}
}
解决方法:按固定顺序获取锁
java复制public class LivelockDemo {
static class Person {
boolean isMovingRight = true;
void meet(Person other) {
while (other.isMovingRight == this.isMovingRight) {
// 两人互相让路但总是同方向
isMovingRight = !isMovingRight;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
new Thread(() -> p1.meet(p2)).start();
new Thread(() -> p2.meet(p1)).start();
}
}
解决方法:引入随机性或其他协调机制
java复制public class ConcurrentHashMapDemo {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 线程安全的putIfAbsent
map.putIfAbsent("key", 1);
// 原子更新
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
// 并行操作
map.forEach(2, (k, v) ->
System.out.println(k + "=" + v + " by " + Thread.currentThread().getName()));
}
}
java复制public class CopyOnWriteDemo {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
list.add("item2");
// 迭代过程中可以安全修改
for (String item : list) {
System.out.println(item);
list.add("newItem");
}
System.out.println("Final list: " + list);
}
}
适用场景:读多写少,迭代操作频繁
java复制public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// 生产者
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
queue.put(i);
System.out.println("Produced: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 消费者
new Thread(() -> {
try {
while (true) {
Integer item = queue.take();
System.out.println("Consumed: " + item);
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
java复制public class CompletableFutureDemo {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
System.out.println("Calculating...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
}).thenApply(result -> result * 2)
.thenAccept(result ->
System.out.println("Final result: " + result));
System.out.println("Main thread continues...");
try {
Thread.sleep(2000); // 等待异步任务完成
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
java复制public class CompletableFutureCombine {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future1 = CompletableFuture
.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture
.supplyAsync(() -> 20);
CompletableFuture<Integer> combined = future1
.thenCombine(future2, (a, b) -> a + b);
System.out.println("Combined result: " + combined.get());
}
}
java复制public class CompletableFutureException {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("Error occurred");
}
return "Success";
}).exceptionally(ex -> {
System.out.println("Exception: " + ex.getMessage());
return "Recovered";
}).thenAccept(System.out::println);
}
}
java复制public class SimpleCounter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
java复制public class SynchronizedCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
java复制public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
java复制public class LongAdderCounter {
private LongAdder count = new LongAdder();
public void increment() {
count.increment();
}
public long getCount() {
return count.sum();
}
}
性能比较:
java复制public class ProducerConsumer {
private static class Producer implements Runnable {
private BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
queue.put(i);
System.out.println("Produced: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Consumer implements Runnable {
private BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer item = queue.take();
System.out.println("Consumed: " + item);
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
new Thread(new Producer(queue)).start();
new Thread(new Consumer(queue)).start();
}
}
java复制public class ProducerConsumerWaitNotify {
private static List<Integer> buffer = new ArrayList<>();
private static final int MAX_SIZE = 5;
private static class Producer implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
synchronized (buffer) {
while (buffer.size() == MAX_SIZE) {
buffer.wait();
}
buffer.add(i);
System.out.println("Produced: " + i);
buffer.notifyAll();
}
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Consumer implements Runnable {
@Override
public void run() {
try {
while (true) {
synchronized (buffer) {
while (buffer.isEmpty()) {
buffer.wait();
}
int item = buffer.remove(0);
System.out.println("Consumed: " + item);
buffer.notifyAll();
}
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
}
java复制public class SimpleCache<K, V> {
private final Map<K, V> cache = new HashMap<>();
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
}
java复制public class SynchronizedCache<K, V> {
private final Map<K, V> cache = new HashMap<>();
public synchronized V get(K key) {
return cache.get(key);
}
public synchronized void put(K key, V value) {
cache.put(key, value);
}
}
java复制public class ConcurrentCache<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
public V computeIfAbsent(K key, Function<K, V> mappingFunction) {
return cache.computeIfAbsent(key, mappingFunction);
}
}
java复制public class ExpiringCache<K, V> {
private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService cleaner = Executors.newScheduledThreadPool(1);
private static class CacheEntry<V> {
final V value;
final long expiryTime;
CacheEntry(V value, long ttl) {
this.value = value;
this.expiryTime = System.currentTimeMillis() + ttl;
}
boolean isExpired() {
return System.currentTimeMillis() > expiryTime;
}
}
public ExpiringCache() {
cleaner.scheduleAtFixedRate(this::cleanup, 1, 1, TimeUnit.SECONDS);
}
public void put(K key, V value, long ttl) {
cache.put(key, new CacheEntry<>(value, ttl));
}
public V get(K key) {
CacheEntry<V> entry = cache.get(key);
if (entry == null || entry.isExpired()) {
return null;
}
return entry.value;
}
private void cleanup() {
cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
}
public void shutdown() {
cleaner.shutdown();
}
}
优先使用高级并发工具:
避免过早优化:
注意资源清理:
测试并发代码:
文档化线程安全保证:
避免常见陷阱:
监控和调试:
Java 19引入的虚拟线程(轻量级线程)将改变并发编程方式:
java复制// 预览功能,Java 19+
public class VirtualThreadDemo {
public static void main(String[] args) {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
Thread.sleep(1000);
System.out.println("Task completed");
return null;
});
}
}
}
}
特点:
java复制// 预览功能,Java 19+
public class StructuredConcurrencyDemo {
public static void main(String[] args) {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<Integer> future1 = scope.fork(() -> task1());
Future<String> future2 = scope.fork(() -> task2());
scope.join();
scope.throwIfFailed();
System.out.println(future1.resultNow() + future2.resultNow());
} catch (Exception e) {
e.printStackTrace();
}
}
static int task1() throws InterruptedException {
Thread.sleep(1000);
return 42;
}
static String task2() throws InterruptedException {
Thread.sleep(1500);
return "Hello";
}
}
优点:
使用JFR(Java Flight Recorder)分析锁竞争:
bash复制java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder \
-XX:StartFlightRecording=duration=60s,filename=recording.jfr \
YourApplication
然后使用JD