MST

星途 面试题库

面试题:Java中如何确保多线程环境下对象的内存访问线程安全

在Java多线程编程中,假设有一个共享的对象,多个线程会同时访问并修改该对象的属性值。请说明至少两种确保对该对象内存访问线程安全的方式,并简要阐述其原理。
50.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 使用synchronized关键字
    • 原理synchronized关键字可以修饰方法或代码块。当一个线程进入被synchronized修饰的方法或代码块时,它会自动获取对象的锁(如果是静态方法,则获取类的锁)。其他线程在该线程持有锁期间无法进入相同对象(或类)的被synchronized修饰的方法或代码块,从而保证同一时间只有一个线程能够访问并修改共享对象的属性值,避免了数据竞争,达到线程安全。例如:
    public class SharedObject {
        private int value;
        public synchronized void increment() {
            value++;
        }
        public synchronized int getValue() {
            return value;
        }
    }
    
  2. 使用ReentrantLock
    • 原理ReentrantLock是Java 5.0引入的一种显式锁。它提供了比synchronized更灵活的锁控制。线程在访问共享对象前调用lock()方法获取锁,访问结束后调用unlock()方法释放锁。在锁被一个线程持有时,其他线程尝试获取锁会被阻塞,直到锁被释放,从而保证对共享对象的线程安全访问。例如:
    import java.util.concurrent.locks.ReentrantLock;
    public class SharedObject2 {
        private int value;
        private ReentrantLock lock = new ReentrantLock();
        public void increment() {
            lock.lock();
            try {
                value++;
            } finally {
                lock.unlock();
            }
        }
        public int getValue() {
            lock.lock();
            try {
                return value;
            } finally {
                lock.unlock();
            }
        }
    }
    
  3. 使用Atomic原子类
    • 原理:Java的java.util.concurrent.atomic包下的原子类(如AtomicIntegerAtomicLong等)利用硬件级别的原子操作来保证对数据的操作是原子性的,不需要额外的锁机制。例如AtomicIntegerincrementAndGet()方法,它会以原子方式将当前值加1并返回新值。这是通过CAS(Compare - And - Swap)操作实现的,CAS操作会比较内存中的值和预期值,如果相等则更新为新值,这个过程是原子的,从而保证了多线程环境下对共享对象属性值修改的线程安全。例如:
    import java.util.concurrent.atomic.AtomicInteger;
    public class SharedObject3 {
        private AtomicInteger value = new AtomicInteger();
        public void increment() {
            value.incrementAndGet();
        }
        public int getValue() {
            return value.get();
        }
    }