Threads Collider尝试在“完全相同”的时刻对多个线程执行所需的操作,以增加出现由竞争条件或死锁引起的问题的机会。
code@RepeatedTest(10)
void Thread_safe_adding_to_list() {
// Given
List<String> list = new ArrayList<>(); // <-- NOT thread safe
// When
try (ThreadsCollider threadsCollider =
threadsCollider()
.withAction(() -> list.add("bar"))
.times(Processors.ALL) // run action on all available processors
.build()) {
threadsCollider.collide();
}
// Then
then(list).hasSize(Processors.ALL).containsOnly("bar");
}/code
死锁测试:
codevoid update1(List<Integer> list1, List<Integer> list2) {
synchronized (list1) {
list1.add(1);
synchronized (list2) {
list2.add(1);
}
}
}
void update2(List<Integer> list2, List<Integer> list1) {
synchronized (list2) {
list2.add(1);
synchronized (list1) {
list1.add(1);
}
}
}/code
希望同时执行这两个方法以显示死锁:
code@RepeatedTest(10)
void Detect_deadlock() {
// Given
List<Exception> exceptions = new ArrayList<>();
// When
try (ThreadsCollider collider =
threadsCollider()
.withAction(() -> update1(list1, list2), "update1") // add action name for better logs readability
.times(Processors.HALF)
.withAction(() -> update2(list2, list1), "update2") // add action name for better logs readability
.times(Processors.HALF)
.withThreadsExceptionsConsumer(exceptions::add) // save threads exceptions
.withAwaitTerminationTimeout(100)
.asMilliseconds()
.build()) {
collider.collide();
}
// Then
then(exceptions).isEmpty();
}/code
某些测试将失败并显示以下消息:
codejava.lang.AssertionError:
Expecting empty but was: pl.amazingcode.threadscollider.UnfinishedThreads:
There are threads that have not completed within the specified timeout: 100 MILLISECONDS
Check if there are any deadlocks and fix them.
If there are no deadlocks, increase timeout.
Deadlocked threads:
"collider-pool-thread-2 update1" daemon prio=5 Id=24 BLOCKED on java.util.ArrayList@6c6cb480 owned by "collider-pool-thread-3 update2" Id=25
"collider-pool-thread-3 update2" daemon prio=5 Id=25 BLOCKED on java.util.ArrayList@3eb738bb owned by "collider-pool-thread-2 update1" Id=24
/code
依赖:
code<dependency>
<groupId>pl.amazingcode</groupId>
<artifactId>threads-collider</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>/code