数据空间研究院-后端试题
题目一:线程安全的链表
描述:
实现一个线程安全的链表类 ThreadSafeLinkedList,支持以下操作:
- add(T element) - 在链表末尾添加元素。
- remove(T element) - 移除链表中的指定元素。
- contains(T element) - 检查链表中是否包含指定元素。
要求:
• 使用 Java 内置的同步机制实现线程安全。
• 不能使用 Java 内置的同步容器类(如 Collections.synchronizedList 或 CopyOnWriteArrayList)。
实现
package threadsafelist;
import java.util.Objects;
/**
* 实现一个线程安全的链表类 threadsafelist.ThreadSafeLinkedList,支持以下操作:
* 1. add(T element) - 在链表末尾添加元素。
* 2. remove(T element) - 移除链表中的指定元素。
* 3. contains(T element) - 检查链表中是否包含指定元素。
* @param <T>
*/
public class ThreadSafeLinkedList<T> {
private static class Node<T> {
T value;
Node<T> next;
Node(T value) {
this.value = value;
}
}
private final Node<T> head;
private final Node<T> tail;
public ThreadSafeLinkedList() {
head = new Node<>(null);
tail = new Node<>(null);
head.next = tail;
}
public synchronized void add(T element) {
Node<T> newNode = new Node<>(element);
Node<T> current = head;
while (current.next != tail) {
current = current.next;
}
current.next = newNode;
newNode.next = tail;
}
public synchronized boolean remove(T element) {
Node<T> prev = head;
Node<T> current = head.next;
while (current != tail) {
if (Objects.equals(element, current.value)) {
prev.next = current.next;
return true;
}
prev = current;
current = current.next;
}
return false;
}
public synchronized boolean contains(T element) {
Node<T> current = head.next;
while (current != tail) {
if (Objects.equals(element, current.value)) {
return true;
}
current = current.next;
}
return false;
}
}
测试代码
import threadsafelist.ThreadSafeLinkedList;
public class Main {
public static void main(String[] args) {
ThreadSafeLinkedList<String> list = new ThreadSafeLinkedList<>();
// 线程1添加元素
new Thread(() -> {
list.add("A");
list.add("B");
}).start();
// 线程2检查元素
new Thread(() -> {
System.out.println(list.contains("A")); // 可能输出true或false
}).start();
}
}
执行结果
“true”
题目二:自定义注解与反射
描述:
编写一个自定义注解 @LogExecutionTime,并实现一个注解处理器,当标记有该注解的方法被调用时,记录方法的执行时间并输出。
要求:
- 创建 @LogExecutionTime 注解。
- 编写一个代理类或使用 AOP(如 Spring AOP)来拦截方法调用,记录并输出方法执行时间。
- 提供一个示例类和方法,展示注解的实际应用效果。
- 需要考虑跨线程透传问题
实现
功能代码如下:
package anotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
package anotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class PerformanceHandler implements InvocationHandler {
private final Object target;
private static final ConcurrentMap<String, Long> methodStats = new ConcurrentHashMap<>();
public PerformanceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取当前时间
long start = System.currentTimeMillis();
try {
return method.invoke(target, args);
} finally {
long end = System.currentTimeMillis();
//计算执行时间
long executionTime = end - start;
// 获取方法签名
String methodSignature = method.getDeclaringClass().getName() + "." + method.getName();
// 记录当前方法执行时间
methodStats.put(methodSignature, executionTime);
// 输出执行时间(支持跨线程)
System.out.printf("[%s] Method %s executed in %d ms%n", // ms 而不是 ns
Thread.currentThread().getName(),
methodSignature,
executionTime);
}
}
public static Map<String, Long> getMethodStats() {
return new HashMap<>(methodStats);
}
}
测试代码如下:
package anotation;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public static <T> T createProxy(Class<T> interfaceClass, T target) {
Object proxy = Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
new PerformanceHandler(target)
);
// 运行时类型检查
if (interfaceClass.isInstance(proxy)) {
return interfaceClass.cast(proxy);
}
throw new ClassCastException("Generated proxy does not implement interface: " + interfaceClass.getName());
}
}
package anotation;
public interface ExampleService {
void processData();
String fetchData(String key);
}
package anotation;
public class ExampleServiceImpl implements ExampleService{
@Override
@LogExecutionTime
public void processData() {
try {
Thread.sleep(500); // 模拟处理耗时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
@LogExecutionTime
public String fetchData(String key) {
try {
Thread.sleep(200); // 模拟网络请求
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Data for " + key;
}
}
package anotation;
public class Main {
public static void main(String[] args) throws InterruptedException {
ExampleService service = ProxyFactory.createProxy(ExampleService.class, new ExampleServiceImpl());
// 主线程调用
service.processData();
// 多线程调用
Thread thread1 = new Thread(() -> service.fetchData("key1"));
Thread thread2 = new Thread(() -> service.fetchData("key2"));
thread1.start();
thread2.start();
thread1.join();
thread2.join();
// 查看统计数据
System.out.println("\nMethod execution statistics:");
PerformanceHandler.getMethodStats().forEach((k, v) ->
System.out.printf("Method %s last time: %d ms%n", k, v));
}
}
执行结果:
[main] Method anotation.ExampleService.processData executed in 504 ms
[Thread-2] Method anotation.ExampleService.fetchData executed in 213 ms
[Thread-1] Method anotation.ExampleService.fetchData executed in 213 ms
Method execution statistics:
Method anotation.ExampleService.processData last time: 504 ms
Method anotation.ExampleService.fetchData last time: 213 ms
题目三:简化的消息队列
描述
实现一个简化的消息队列类 SimpleMessageQueue,支持以下操作:
- send(T message) - 发送消息。
- receive() - 接收消息,若队列为空,阻塞直到有消息可接收。
要求:
• 使用 java.util.concurrent 包中的工具类来实现。
• 需要保证 send 和 receive 操作的线程安全。
• 提供单元测试,验证消息队列的正确性。
实现
功能代码
package simplemessagequeue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class SimpleMessageQueue<T> {
private final BlockingQueue<T> queue = new LinkedBlockingQueue<>();
// 发送消息
public void send(T message) {
try {
queue.put(message);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Send interrupted", e);
}
}
// 接收消息,若队列为空则阻塞
public T receive() {
try {
return queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Receive interrupted", e);
}
}
}
测试代码
package simplemessagequeue;
public class SimpleMessageQueueTest {
public static void main(String[] args) throws InterruptedException {
SimpleMessageQueue<String> queue = new SimpleMessageQueue<>();
// 测试单线程收发
queue.send("hello");
assert "hello".equals(queue.receive());
// 测试多线程收发
Thread sender = new Thread(() -> {
for (int i = 0; i < 5; i++) {
queue.send("msg" + i);
}
});
Thread receiver = new Thread(() -> {
for (int i = 0; i < 5; i++) {
String msg = queue.receive();
System.out.println("Received: " + msg);
}
});
sender.start();
receiver.start();
sender.join();
receiver.join();
System.out.println("All tests passed.");
}
}
运行结果
Received: hello
Received: msg0
Received: msg1
Received: msg2
Received: msg3
All tests passed.