使用Java ThreadSanitizer发现data race
这个功能我没有明白为什么没有加入默认的Java版本中,这个东西应该是很有用的东西。可能是效果不是特别好,也可能是存在某些明显的性能开销,以至于在代码中维护这些东西成本非常好而收益很低。
UPDATE: 效率是真的低,我感觉可能是10x-20x差不多左右。
https://runtimeverification.com/blog/detecting-popular-data-races-in-java-using-rv-predict/
openjdk/tsan: https://openjdk.org/projects/tsan
编译命令是
use-java13; unset CLASSPATH; bash configure –prefix=`pwd`/installed ; make CONF=linux-x86_64-server-release clean install
简单的Java程序,多个线程共同修改某个变量
package com.starrocks.lab;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadDataRaceCase {
int value;
public class Adder implements Runnable {
int index;
int duration;
int tick;
public Adder(int index, int duration) {
this.index = index;
this.duration = duration;
this.tick = 0;
}
@Override
public void run() {
System.out.println("Thread " + index + " started...");
long begin = System.currentTimeMillis();
while (true) {
value += 1;
tick += 1;
if (tick % 100 == 0) {
long now = System.currentTimeMillis();
if ((now - begin) > duration * 1000) {
break;
}
}
}
System.out.println("Thread " + index + " stopped...");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadDataRaceCase t = new ThreadDataRaceCase();
t.value = 0;
int number = 16;
int duration = 10;
Adder adder[] = new Adder[number];
ExecutorService executor = Executors.newFixedThreadPool(number);
for (int i = 0; i < number; i++) {
adder[i] = t.new Adder(i, duration);
executor.submit(adder[i]);
}
executor.shutdown();
executor.awaitTermination(2 * duration, TimeUnit.SECONDS);
}
}
运行起来可以发现错误是:需要使用 `java -XX:+ThreadSanitizer` 来运行
sandbox-cloud :: src/main/java ‹master*› » javac com/starrocks/lab/ThreadDataRaceCase.java
sandbox-cloud :: src/main/java ‹master*› » java -XX:+ThreadSanitizer com/starrocks/lab/ThreadDataRaceCase
Thread 1 started...
Thread 3 started...
==================
WARNING: ThreadSanitizer: data race (pid=227159)
Read of size 4 at 0x000101c92a64 by thread T18:
#0 com.starrocks.lab.ThreadDataRaceCase$Adder.run()V ThreadDataRaceCase.java:26
#1 java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object; Executors.java:515
#2 java.util.concurrent.FutureTask.run()V FutureTask.java:264
#3 java.util.concurrent.ThreadPoolExecutor.runWorker(Ljava/util/concurrent/ThreadPoolExecutor$Worker;)V ThreadPoolExecutor.java:1130
#4 java.util.concurrent.ThreadPoolExecutor$Worker.run()V ThreadPoolExecutor.java:630
#5 java.lang.Thread.run()V Thread.java:832
#6 (Generated Stub) <null>
Previous write of size 4 at 0x000101c92a64 by thread T16:
#0 com.starrocks.lab.ThreadDataRaceCase$Adder.run()V ThreadDataRaceCase.java:26
#1 java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object; Executors.java:515
#2 java.util.concurrent.FutureTask.run()V FutureTask.java:264
#3 java.util.concurrent.ThreadPoolExecutor.runWorker(Ljava/util/concurrent/ThreadPoolExecutor$Worker;)V ThreadPoolExecutor.java:1130
#4 java.util.concurrent.ThreadPoolExecutor$Worker.run()V ThreadPoolExecutor.java:630
#5 java.lang.Thread.run()V Thread.java:832
#6 (Generated Stub) <null>
Thread T18 (tid=227178, running) created by thread T1 at:
#0 pthread_create <null> (libtsan.so.0+0x615d8)
#1 os::create_thread(Thread*, os::ThreadType, unsigned long) /home/disk4/zhangyan/repo/tsan/src/hotspot/os/linux/os_linux.cpp:927 (libjvm.so+0xb4e649)
#2 java.lang.Thread.start()V Thread.java:801
#3 java.util.concurrent.ThreadPoolExecutor.addWorker(Ljava/lang/Runnable;Z)Z ThreadPoolExecutor.java:939
#4 java.util.concurrent.ThreadPoolExecutor.execute(Ljava/lang/Runnable;)V ThreadPoolExecutor.java:1345
#5 java.util.concurrent.AbstractExecutorService.submit(Ljava/lang/Runnable;)Ljava/util/concurrent/Future; AbstractExecutorService.java:118
#6 com.starrocks.lab.ThreadDataRaceCase.main([Ljava/lang/String;)V ThreadDataRaceCase.java:49
#7 (Generated Stub) <null>
Thread T16 (tid=227176, running) created by thread T1 at:
#0 pthread_create <null> (libtsan.so.0+0x615d8)
#1 os::create_thread(Thread*, os::ThreadType, unsigned long) /home/disk4/zhangyan/repo/tsan/src/hotspot/os/linux/os_linux.cpp:927 (libjvm.so+0xb4e649)
#2 java.lang.Thread.start()V Thread.java:801
#3 java.util.concurrent.ThreadPoolExecutor.addWorker(Ljava/lang/Runnable;Z)Z ThreadPoolExecutor.java:939
#4 java.util.concurrent.ThreadPoolExecutor.execute(Ljava/lang/Runnable;)V ThreadPoolExecutor.java:1345
#5 java.util.concurrent.AbstractExecutorService.submit(Ljava/lang/Runnable;)Ljava/util/concurrent/Future; AbstractExecutorService.java:118
#6 com.starrocks.lab.ThreadDataRaceCase.main([Ljava/lang/String;)V ThreadDataRaceCase.java:49
#7 (Generated Stub) <null>