MST
星途 面试题库

面试题:Java内存模型下的锁机制与内存语义

阐述Java中synchronized关键字在Java内存模型下的内存语义,以及它如何保证原子性、可见性和有序性。
42.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

synchronized关键字的内存语义

  1. 锁的获取:当线程获取synchronized锁时,Java内存模型会把该线程对应的本地内存置为无效。这意味着线程必须从主内存中重新读取共享变量的值。
  2. 锁的释放:当线程释放synchronized锁时,Java内存模型会把该线程对应的本地内存中的共享变量刷新到主内存中。这样,其他线程在获取到锁后,就能看到最新的值。

对原子性的保证

  1. 原理:synchronized关键字通过对临界区代码进行加锁,同一时刻只有一个线程能够进入临界区执行代码。在锁未释放前,其他线程无法进入,从而保证了临界区内代码执行的原子性。
  2. 示例
public class AtomicExample {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
}

在上述代码中,increment方法被synchronized修饰,多个线程调用该方法时,只有一个线程能执行count++操作,不会出现并发问题,保证了count++操作的原子性。

对可见性的保证

  1. 原理:如前面内存语义所述,线程释放锁时会将本地内存中的共享变量刷新到主内存,线程获取锁时会将本地内存置为无效并从主内存重新读取共享变量。这确保了一个线程对共享变量的修改,在其他线程获取锁后是可见的。
  2. 示例
public class VisibilityExample {
    private int num = 0;
    public synchronized void update() {
        num = 1;
    }
    public synchronized void read() {
        System.out.println(num);
    }
}

在上述代码中,当一个线程调用update方法修改num后释放锁,num的值被刷新到主内存。其他线程调用read方法获取锁时,从主内存读取到的就是最新的num值,保证了可见性。

对有序性的保证

  1. 原理:synchronized关键字不仅保证了同一时刻只有一个线程能执行临界区代码,还禁止了指令重排序。在获取锁时,会将本地内存置为无效,强制从主内存读取共享变量;在释放锁时,会将本地内存中的共享变量刷新到主内存。这一系列操作使得临界区内的代码按照顺序执行,不会发生指令重排序。
  2. 示例
public class OrderingExample {
    private int a = 0;
    private int b = 0;
    public synchronized void write() {
        a = 1;
        b = 2;
    }
    public synchronized void read() {
        System.out.println(b);
        System.out.println(a);
    }
}

在上述代码中,write方法内的a = 1b = 2不会发生指令重排序,read方法内的打印操作也会按照顺序执行,从而保证了有序性。