面试题答案
一键面试多线程并发访问Java静态变量和静态方法的问题
- 数据不一致问题:多个线程同时访问和修改静态变量时,可能会导致数据不一致。因为线程的执行顺序是不确定的,可能会出现一个线程读取了静态变量的值,然后另一个线程修改了该值,第一个线程再进行操作时,使用的就是过期的数据。
- 竞态条件(Race Condition):静态方法如果涉及对静态变量的操作,在多线程环境下也会出现竞态条件。多个线程竞争对静态变量的操作权,导致程序运行结果不可预测。
确保静态变量在多线程环境下线程安全的方法
- 使用
synchronized
关键字:- 修饰静态方法:当
synchronized
修饰静态方法时,锁对象是该类的Class
对象。所有线程访问该静态方法时,需要获取该类的Class
对象的锁。
public class StaticThreadSafeExample { private static int count = 0; public static synchronized void increment() { count++; } public static int getCount() { return count; } }
- 修饰静态代码块:同样可以通过
synchronized
修饰静态代码块来保证线程安全,锁对象同样是该类的Class
对象。
public class StaticThreadSafeExample2 { private static int count = 0; static { synchronized (StaticThreadSafeExample2.class) { // 这里可以进行一些初始化操作,且线程安全 count = 10; } } public static int getCount() { return count; } }
- 修饰静态方法:当
- 使用锁(
Lock
接口):java.util.concurrent.locks.Lock
接口提供了更灵活的锁机制。可以使用ReentrantLock
来保证静态变量的线程安全。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class StaticThreadSafeWithLock {
private static int count = 0;
private static final Lock lock = new ReentrantLock();
public static void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public static int getCount() {
return count;
}
}
在上述代码中,ReentrantLock
保证了在同一时间只有一个线程可以执行increment
方法中修改静态变量count
的代码,从而确保了线程安全。在使用Lock
时,需要注意在try - finally
块中进行加锁和解锁操作,以避免异常情况下锁未释放的问题。