面试题答案
一键面试隐患及原因
- 资源竞争
- 原因:多个线程同时访问并修改通过引用传递的共享资源。例如,多个线程可能同时调用一个函数,该函数接收一个共享数据结构的引用,并对其进行写操作。由于线程执行的不确定性,可能导致数据修改顺序混乱,从而产生资源竞争问题。
- 示例:
import threading
shared_list = []
def append_number_ref(num):
shared_list.append(num)
threads = []
for i in range(10):
t = threading.Thread(target = append_number_ref, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
print(shared_list)
在这个例子中,如果多个线程同时执行append_number_ref
函数,由于线程执行的不确定性,shared_list
的最终结果可能并非按顺序添加元素,这就是资源竞争的表现。
- 数据一致性
- 原因:多个线程对共享资源(通过引用传递)的读写操作没有正确同步。当一个线程正在修改共享数据,而另一个线程同时读取该数据时,可能读到不一致的数据状态。
- 示例:
class Data {
int value;
}
public class DataConsistencyProblem {
public static void main(String[] args) {
Data data = new Data();
Thread writerThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
data.value = i;
}
});
Thread readerThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
System.out.println("Read value: " + data.value);
}
});
writerThread.start();
readerThread.start();
}
}
在这个Java代码中,readerThread
可能会读到data.value
的不一致值,因为writerThread
对data.value
的修改和readerThread
的读取没有同步。
应对策略
- 使用锁机制
- 原理:通过加锁,确保在同一时间只有一个线程能够访问共享资源,从而避免资源竞争和数据不一致问题。
- Python示例:
import threading
shared_list = []
lock = threading.Lock()
def append_number_ref(num):
with lock:
shared_list.append(num)
threads = []
for i in range(10):
t = threading.Thread(target = append_number_ref, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
print(shared_list)
- Java示例:
class Data {
int value;
final Object lock = new Object();
}
public class DataConsistencySolution {
public static void main(String[] args) {
Data data = new Data();
Thread writerThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
synchronized (data.lock) {
data.value = i;
}
}
});
Thread readerThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
synchronized (data.lock) {
System.out.println("Read value: " + data.value);
}
}
});
writerThread.start();
readerThread.start();
}
}
- 使用线程本地存储(Thread - Local Storage)
- 原理:为每个线程提供独立的变量副本,避免线程间共享数据,从而从根本上解决资源竞争和数据一致性问题。
- Python示例:
import threading
local_data = threading.local()
def process_data():
local_data.value = threading.current_thread().name
print(f"Thread {local_data.value} has its own data: {local_data.value}")
threads = []
for i in range(3):
t = threading.Thread(target = process_data)
threads.append(t)
t.start()
for t in threads:
t.join()
- Java示例:
public class ThreadLocalExample {
private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
threadLocal.set(1);
System.out.println("Thread 1: " + threadLocal.get());
});
Thread thread2 = new Thread(() -> {
threadLocal.set(2);
System.out.println("Thread 2: " + threadLocal.get());
});
thread1.start();
thread2.start();
}
}