面试题答案
一键面试StringTokenizer 与 String split 方法在多线程环境下的问题
- StringTokenizer:
- 线程安全问题:
StringTokenizer
不是线程安全的。多个线程同时调用其方法(如nextToken()
)时,可能会导致内部状态不一致,因为它的内部状态(如当前位置等)没有进行同步处理。例如,一个线程在处理到一半时,另一个线程可能修改了其内部指针,导致结果错误。
- 线程安全问题:
- String split:
- 线程安全问题:
String split
方法本身不涉及内部状态维护,它根据传入的字符串和分隔符直接生成结果数组,所以在多线程环境下,只要不共享同一个String
对象进行拆分操作(一般情况下不会共享同一个String
对象拆分),基本不会有线程安全问题。但如果多个线程共享同一个String
对象并调用split
方法,可能会因对String
对象的竞争而导致性能问题。
- 线程安全问题:
优化策略
- 针对 StringTokenizer:
- 同步块:可以在调用
StringTokenizer
方法时使用synchronized
块来同步访问。例如:
StringTokenizer tokenizer; synchronized (tokenizer) { String token = tokenizer.nextToken(); }
- 使用线程安全替代:可以使用
Scanner
类替代StringTokenizer
,Scanner
虽然也不是完全线程安全的,但可以通过同步块或使用ConcurrentHashMap
等线程安全的数据结构来管理共享资源。例如,将Scanner
对象封装在一个线程安全的类中,并对其关键方法使用同步机制。
- 同步块:可以在调用
- 针对 String split:
- 避免共享对象:确保每个线程使用独立的
String
对象进行拆分操作,避免多个线程同时操作同一个String
对象。
- 避免共享对象:确保每个线程使用独立的
多线程测试代码验证优化效果
- 测试 StringTokenizer:
import java.util.StringTokenizer; public class StringTokenizerThreadTest { private static StringTokenizer tokenizer; private static final String testString = "a,b,c,d"; public static class TokenizerThread extends Thread { @Override public void run() { synchronized (tokenizer) { while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(","); System.out.println(Thread.currentThread().getName() + " : " + token); } } } } public static void main(String[] args) { tokenizer = new StringTokenizer(testString, ","); TokenizerThread thread1 = new TokenizerThread(); TokenizerThread thread2 = new TokenizerThread(); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
- 测试 String split:
public class StringSplitThreadTest { private static final String testString = "a,b,c,d"; public static class SplitThread extends Thread { @Override public void run() { String[] parts = testString.split(","); for (String part : parts) { System.out.println(Thread.currentThread().getName() + " : " + part); } } } public static void main(String[] args) { SplitThread thread1 = new SplitThread(); SplitThread thread2 = new SplitThread(); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
在上述代码中,StringTokenizerThreadTest
通过synchronized
块解决StringTokenizer
的线程安全问题,StringSplitThreadTest
通过确保每个线程使用独立操作(这里split
方法基于传入的String
对象生成独立数组,不涉及共享状态修改)来展示String split
在多线程环境下的情况。如果不使用同步块对StringTokenizer
进行保护,可能会出现结果混乱的情况,而使用同步块后结果将是正确的。String split
由于其自身特性,在多线程下只要不共享同一对象拆分基本不会出现线程安全问题,上述代码也验证了这一点。