为何第二个线程执行相同String替换操作耗时远低于第一个?
为什么第二个线程的字符串替换操作耗时远低于第一个?
首先要明确:你代码里的计时逻辑完全错误,你打印的t1和t2时间,根本不是replaceAll操作的实际耗时,而是创建并启动线程的耗时。
核心原因拆解
- 线程启动的本质:调用
Thread.start()只是告诉JVM把线程加入调度队列,等待CPU分配时间片,这个过程本身耗时极短。第一次启动线程时,JVM需要完成线程栈初始化、调度器首次交互等额外工作,第二次启动时这些初始化已经完成,所以启动速度更快,这是你看到时间差异的直接原因。 - 真正的业务耗时没被统计:线程里的
replaceAll和打印操作是在后台异步执行的,你的s到e只记录了调用start()方法的往返时间,完全没覆盖实际的字符串替换逻辑。 - Pattern缓存的额外影响:
String.replaceAll()底层依赖Pattern.compile()编译正则表达式,而Pattern类会缓存已编译的正则实例。第一个线程第一次调用时需要编译"E",有额外开销;第二个线程调用时直接复用缓存的Pattern,这会让replaceAll本身的执行更快,但这不是你看到计时差异的主要原因——因为你的计时根本没统计这部分时间。
修正后的代码示例
要正确统计线程中任务的耗时,需要用join()等待线程执行完成:
public class Main { public static void main(String[] args) throws InterruptedException { final String[] test = { "YKWV57I4OYEBH1JMMLGDRTH66HO6OIOJHMLASA29WHPD5OOYMQY0URO05901PXAOQUU2KDIGWOTMX0YR7LBHE7Z6Z55R9GG8NWD13V70BRG5L70L65GHZFNI6ZEA349BHLDO3LQLNS6RGL9NQKMKK1KJ91AH68PKIGYM2Q772WWWAV20ZRYXUWCERXQUW8SF67OG4LEY19VPJ9ZXO9II8S39JRJTMOI9JW4CYYUGJ2YYWE7C6FTL71NJKLEACUUKW1O68P0EDMR3XGWJY1F6179Y87B7JCYBY35QEAI67YJQ944APUJX7SKD8DR9XIH6KB0V0TMLKPCNOSFIMSONH822GSKDGR3B05M1T9YK8RH7GPTQDVINR1SKG92OCMNW0GZNBV77JYOJ32O3CLJWCIZUQXUZAMEKQLCO8E47UCUV64U630GHAZ34M05QI7504ZR53KLSYSDKFQLE3JSZDKL4VLGY456LKND4Z49Y3QCED2YOSMHH7FVZGA1HXM" }; // 统计第一个线程的实际执行耗时 Thread t1 = new Thread(() -> { long s = System.currentTimeMillis(); test[0] = test[0].replaceAll("E", " 11111 "); long e = System.currentTimeMillis(); System.out.println("t1 replaceAll耗时: " + (e - s) + "ms"); System.out.println(test[0] + " is test[0] for thread 1"); }); long startT1 = System.currentTimeMillis(); t1.start(); t1.join(); // 等待线程执行完成 long endT1 = System.currentTimeMillis(); System.out.println("t1从启动到完成总耗时: " + (endT1 - startT1) + "ms"); // 统计第二个线程的实际执行耗时 Thread t2 = new Thread(() -> { long s = System.currentTimeMillis(); test[0] = test[0].replaceAll("E", " 22222 "); long e = System.currentTimeMillis(); System.out.println("t2 replaceAll耗时: " + (e - s) + "ms"); System.out.println(test[0] + " is test[0] for thread 2"); }); long startT2 = System.currentTimeMillis(); t2.start(); t2.join(); // 等待线程执行完成 long endT2 = System.currentTimeMillis(); System.out.println("t2从启动到完成总耗时: " + (endT2 - startT2) + "ms"); } }
修正后的预期结果
此时你会看到:
replaceAll的耗时差异主要来自正则缓存:第一次编译正则有额外开销,第二次直接复用,所以t2的replaceAll耗时会略低于t1;- 线程从启动到完成的总耗时差异会很小,因为线程初始化的开销只在第一次出现。
内容的提问来源于stack exchange,提问作者Vishal Singh
相关产品推荐
相关产品推荐

