面试题答案
一键面试可能遇到的问题
- 线程安全问题
- 问题:Lambda表达式可能会捕获外部变量。如果这些变量在多线程环境下被修改,可能导致线程安全问题。例如,在Lambda表达式中使用了非线程安全的集合类,并且多个线程同时对其进行操作。
- 示例:
import java.util.ArrayList;
import java.util.List;
public class LambdaThreadSafetyProblem {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(task);
threads[i].start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Expected size: 10000, Actual size: " + list.size());
}
}
- 分析:这里使用的
ArrayList
是非线程安全的,多个线程同时向其中添加元素会导致数据不一致,最终list
的大小可能不是预期的10000。
- 资源竞争问题
- 问题:当多个线程通过Lambda表达式访问共享资源时,会产生资源竞争。例如,多个线程可能竞争访问同一个文件或者数据库连接等资源。
- 示例:假设我们有一个简单的文件写入操作,多个线程通过Lambda表达式尝试写入文件。
import java.io.FileWriter;
import java.io.IOException;
public class LambdaResourceContention {
public static void main(String[] args) {
String filePath = "test.txt";
Runnable task = () -> {
try (FileWriter writer = new FileWriter(filePath, true)) {
writer.write("Thread " + Thread.currentThread().getName() + " wrote this line.\n");
} catch (IOException e) {
e.printStackTrace();
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(task);
threads[i].start();
}
}
}
- 分析:这里多个线程同时写入同一个文件,如果没有适当的同步机制,文件内容可能会混乱。
- 并行流相关问题
- 问题:在使用并行流(如
Stream.parallel()
)时,如果Lambda表达式中的操作不是无状态的或者不是线程安全的,会导致错误结果。例如,在并行流的map
或reduce
操作中使用有状态的对象。 - 示例:
- 问题:在使用并行流(如
import java.util.Arrays;
import java.util.List;
public class LambdaParallelStreamProblem {
public static void main(String[] args) {
class Counter {
int count = 0;
}
Counter counter = new Counter();
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream().forEach(i -> counter.count++);
System.out.println("Expected count: 5, Actual count: " + counter.count);
}
}
- 分析:在并行流的
forEach
操作中,counter
是有状态的,多个线程同时对其count
进行自增操作,会导致最终结果不准确。
优化策略
- 线程安全优化
- 策略:使用线程安全的类。例如,将非线程安全的
ArrayList
替换为CopyOnWriteArrayList
。 - 示例:
- 策略:使用线程安全的类。例如,将非线程安全的
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class LambdaThreadSafetySolution {
public static void main(String[] args) {
List<Integer> list = new CopyOnWriteArrayList<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(task);
threads[i].start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Expected size: 10000, Actual size: " + list.size());
}
}
- 资源竞争优化
- 策略:使用同步机制,如
synchronized
关键字或者java.util.concurrent
包下的锁机制。对于文件写入操作,可以使用synchronized
块。 - 示例:
- 策略:使用同步机制,如
import java.io.FileWriter;
import java.io.IOException;
public class LambdaResourceContentionSolution {
public static void main(String[] args) {
String filePath = "test.txt";
Object lock = new Object();
Runnable task = () -> {
synchronized (lock) {
try (FileWriter writer = new FileWriter(filePath, true)) {
writer.write("Thread " + Thread.currentThread().getName() + " wrote this line.\n");
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(task);
threads[i].start();
}
}
}
- 并行流优化
- 策略:确保并行流操作中的Lambda表达式是无状态的,或者使用线程安全的累加器。例如,在
reduce
操作中使用AtomicInteger
。 - 示例:
- 策略:确保并行流操作中的Lambda表达式是无状态的,或者使用线程安全的累加器。例如,在
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class LambdaParallelStreamSolution {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
AtomicInteger counter = new AtomicInteger();
numbers.parallelStream().forEach(i -> counter.incrementAndGet());
System.out.println("Expected count: 5, Actual count: " + counter.get());
}
}
通过这些优化策略,可以有效解决Java Lambda表达式在多线程并发场景下的问题,提高并发性能。