I’m trying to test and occur multi-thread concurrency problem.
What i expected is that result should be less than 0, because it is not synchronized.
But the test below fails.
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
class OptionTest {
static class Option {
private int quantity;
public Option(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
public boolean subtract(int quantity){
if(quantity >= this.quantity){
return false;
}
// System.out.println("quantity = " + quantity);
this.quantity -= quantity;
return true;
}
}
@Test
void asyncSubtract() throws InterruptedException {
int numberOfThreads = 100; // Increased number of threads
ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
List<Callable<Boolean>> tasks = new ArrayList<>();
Option option = new Option(201);
for (int i = 0; i < numberOfThreads; i++) {
tasks.add(() -> option.subtract(50));
}
executorService.invokeAll(tasks);
executorService.shutdown();
assertThat(option.getQuantity()).isLessThan(1);
}
}
When after add print on quantity in the substract method, it passed.
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
class OptionTest {
static class Option {
private int quantity;
public Option(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
public boolean subtract(int quantity){
if(quantity >= this.quantity){
return false;
}
System.out.println("quantity = " + quantity);
this.quantity -= quantity;
return true;
}
}
@Test
void asyncSubtract() throws InterruptedException {
int numberOfThreads = 100; // Increased number of threads
ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
List<Callable<Boolean>> tasks = new ArrayList<>();
Option option = new Option(201);
for (int i = 0; i < numberOfThreads; i++) {
tasks.add(() -> option.subtract(50));
}
executorService.invokeAll(tasks);
executorService.shutdown();
assertThat(option.getQuantity()).isLessThan(1);
}
}
Can anyone explain about this code execution result? Is there any JVM magic?