Java内存模型与并发编程

Java内存模型(JMM)是Java并发编程中的核心概念,它定义了线程如何和何时可以看到其他线程修改过的共享变量的值,以及在必须时如何同步的访问共享变量。本文将深入探讨JMM的核心概念和最佳实践。

1. Java内存模型基础

1.1 内存模型的基本概念

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class MemoryModelDemo {
    private int x = 0;  // 共享变量
    private volatile boolean flag = false;  // volatile变量
    
    public void writer() {
        x = 42;  // 写入共享变量
        flag = true;  // 写入volatile变量,确保可见性
    }
    
    public void reader() {
        if (flag) {  // 读取volatile变量
            System.out.println(x);  // 保证能看到writer()中的写入
        }
    }
}

1.2 happens-before关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class HappensBefore {
    private int counter = 0;
    private final Object lock = new Object();
    
    public void increment() {
        synchronized (lock) {  // 同步块建立happens-before关系
            counter++;
        }
    }
    
    public int getCounter() {
        synchronized (lock) {
            return counter;
        }
    }
}

2. volatile关键字

2.1 可见性保证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class VolatileVisibility {
    private volatile boolean flag = false;
    private int data = 0;
    
    public void producer() {
        data = 100;  // 1
        flag = true; // 2 volatile写入
    }
    
    public void consumer() {
        while (!flag) {  // volatile读取
            Thread.yield();
        }
        assert data == 100;  // 一定能看到producer中的写入
    }
}

2.2 禁止重排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class VolatileReordering {
    private volatile int state = 0;
    private int[] data = new int[10];
    
    public void prepare() {
        for (int i = 0; i < data.length; i++) {
            data[i] = i;  // 1
        }
        state = 1;  // 2 volatile写入,确保1不会重排序到2之后
    }
    
    public void use() {
        if (state == 1) {  // volatile读取
            for (int item : data) {
                // 使用数据,确保能看到prepare()中的初始化
                System.out.println(item);
            }
        }
    }
}

3. synchronized关键字

3.1 监视器锁

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class SynchronizedExample {
    private final Object mutex = new Object();
    private int count = 0;
    
    public void increment() {
        synchronized (mutex) {
            count++;  // 临界区
        }
    }
    
    public synchronized int getCount() {  // 方法级同步
        return count;
    }
}

3.2 锁的重入性

1
2
3
4
5
6
7
8
9
public class ReentrantLockExample {
    public synchronized void outer() {
        inner();  // 可以再次获取同一个锁
    }
    
    public synchronized void inner() {
        // 方法体
    }
}

4. final关键字

4.1 final域的重排序规则

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class FinalExample {
    private final int[] arrays;  // final数组引用
    private int[] data;
    
    public FinalExample() {
        arrays = new int[10];  // final写
        for (int i = 0; i < arrays.length; i++) {
            arrays[i] = i;  // 对final域的初始化
        }
        data = new int[10];  // 普通写
    }
}

5. 原子性操作

5.1 原子变量类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class AtomicExample {
    private AtomicInteger counter = new AtomicInteger(0);
    private AtomicReference<String> ref = new AtomicReference<>("initial");
    
    public void increment() {
        counter.incrementAndGet();  // 原子递增
    }
    
    public boolean compareAndSet(String expect, String update) {
        return ref.compareAndSet(expect, update);  // CAS操作
    }
}

6. 内存屏障

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class MemoryBarrierExample {
    private volatile int storeLoad = 0;
    
    public void example() {
        int local = 1;
        // Store-Store屏障
        storeLoad = 1;  // volatile写入
        // Store-Load屏障
        int other = storeLoad;  // volatile读取
        // Load-Load和Load-Store屏障
    }
}

7. 线程安全性实践

7.1 不可变对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public final class ImmutableValue {
    private final int value;
    private final List<Integer> list;
    
    public ImmutableValue(int value, List<Integer> list) {
        this.value = value;
        this.list = new ArrayList<>(list);  // 防御性复制
    }
    
    public int getValue() {
        return value;
    }
    
    public List<Integer> getList() {
        return new ArrayList<>(list);  // 返回副本
    }
}

7.2 安全发布

1
2
3
4
5
6
7
8
9
public class SafePublication {
    private static class Holder {
        static final SafePublication INSTANCE = new SafePublication();
    }
    
    public static SafePublication getInstance() {
        return Holder.INSTANCE;  // 线程安全的延迟初始化
    }
}

最佳实践建议

  1. 优先使用不可变对象
  2. 正确使用volatile关键字
  3. 遵循happens-before规则
  4. 避免过度同步
  5. 使用java.util.concurrent包中的工具类

性能优化技巧

  1. 减少锁竞争
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class LockGranularity {
    private final Map<String, List<String>> map = 
        new ConcurrentHashMap<>();  // 使用并发容器
        
    public void addItem(String key, String item) {
        List<String> list = map.computeIfAbsent(key, 
            k -> new CopyOnWriteArrayList<>());
        list.add(item);  // 细粒度的锁
    }
}
  1. 使用ThreadLocal避免共享
1
2
3
4
5
6
7
8
public class ThreadLocalExample {
    private static final ThreadLocal<DateFormat> dateFormat = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
        
    public String formatDate(Date date) {
        return dateFormat.get().format(date);
    }
}

总结

深入理解Java内存模型对于编写正确的并发程序至关重要。通过合理使用synchronized、volatile等同步机制,以及遵循happens-before规则,我们可以确保程序的线程安全性。同时,通过采用适当的最佳实践和性能优化技巧,可以在保证正确性的同时提高程序的性能。

使用绝夜之城强力驱动