面试题答案
一键面试问题分析
- 线程安全问题:
StringTokenizer
不是线程安全的。在多线程环境下,多个线程同时调用StringTokenizer
的方法(如nextToken()
)可能会导致数据不一致。因为StringTokenizer
内部维护了当前解析位置等状态信息,多个线程并发访问和修改这些状态可能造成混乱。 - 数据竞争:例如,一个线程可能在另一个线程尚未完全处理完当前标记时就改变了字符串的解析位置,导致错误的标记被返回或解析过程混乱。
线程安全解决方案
- 使用同步块(Synchronized Block)
- 原理:通过
synchronized
关键字,将对StringTokenizer
的操作包裹在同步块内,使得同一时间只有一个线程能够进入该同步块,操作StringTokenizer
,从而避免数据竞争。 - 代码实现:
- 原理:通过
import java.util.StringTokenizer;
public class ThreadSafeStringTokenizer {
private final StringTokenizer tokenizer;
public ThreadSafeStringTokenizer(String str, String delim) {
this.tokenizer = new StringTokenizer(str, delim);
}
public synchronized String nextToken() {
if (tokenizer.hasMoreTokens()) {
return tokenizer.nextToken();
}
return null;
}
}
使用示例:
public class Main {
public static void main(String[] args) {
ThreadSafeStringTokenizer tst = new ThreadSafeStringTokenizer("a,b;c", ",;");
String token;
while ((token = tst.nextToken()) != null) {
System.out.println(token);
}
}
}
- 使用ThreadLocal
- 原理:
ThreadLocal
为每个线程提供独立的变量副本。在这里,可以将StringTokenizer
作为ThreadLocal
的变量,每个线程都有自己的StringTokenizer
实例,避免了多线程对同一实例的竞争。 - 代码实现:
- 原理:
import java.util.StringTokenizer;
public class ThreadLocalStringTokenizer {
private static final ThreadLocal<StringTokenizer> threadLocalTokenizer = ThreadLocal.withInitial(() -> null);
public static void setTokenizer(String str, String delim) {
threadLocalTokenizer.set(new StringTokenizer(str, delim));
}
public static String nextToken() {
StringTokenizer tokenizer = threadLocalTokenizer.get();
if (tokenizer != null && tokenizer.hasMoreTokens()) {
return tokenizer.nextToken();
}
return null;
}
}
使用示例:
public class Main {
public static void main(String[] args) {
ThreadLocalStringTokenizer.setTokenizer("a,b;c", ",;");
String token;
while ((token = ThreadLocalStringTokenizer.nextToken()) != null) {
System.out.println(token);
}
}
}