Reputation: 45
I have created a test class. I have a static ExecutorService created like this:
private static ExecutorService service = Executors.newFixedThreadPool(4);
which I close with an @AfterClass function
@AfterClass
public static void afterClass(){
service.shutdown();
try {
if (!service.awaitTermination(1000, TimeUnit.MILLISECONDS)){
service.shutdownNow();
}
} catch (InterruptedException e) {
service.shutdownNow();
}
}
Now to my question have two test cases: Test1
@Test
public void running_a_simple_asynchronous_stage(){
CompletableFuture completableFuture = CompletableFuture.runAsync(()->{
Assert.assertTrue(Thread.currentThread().isDaemon());
sleepForMs(1000);
}, service);
Assert.assertFalse(completableFuture.isDone());
sleepForMs(2000);
Assert.assertTrue(completableFuture.isDone());
}
and
Test2
@Test
public void asynchronously_applying_a_function_on_previous_stage(){
CompletableFuture completableFuture = CompletableFuture.completedFuture("astring").thenApplyAsync(str->{
Assert.assertFalse(Thread.currentThread().isDaemon());
sleepForMs(1000);
return str.toUpperCase();
}, service);
Assert.assertFalse(completableFuture.isDone());
Assert.assertNull(completableFuture.getNow(null));
sleepForMs(2000);
Assert.assertTrue(completableFuture.isDone());
Assert.assertEquals("ASTRING", completableFuture.getNow(null));
}
So my question is why in the first test the current thread is a deamon thread and in the second test is not?
Upvotes: 1
Views: 351
Reputation: 783
Actually the problem is that the exception that is thrown inside CompletableFuture.runAsync
is ignored and since the test frameworks depend on exception to report test failure, the test seems to pass while it has not passed. Add the following to your first test to make it throw exception:
@Test
public void running_a_simple_asynchronous_stage() {
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
Assert.assertTrue(Thread.currentThread().isDaemon());
sleepForMs(1000);
}, service);
completableFuture.join();
Assert.assertFalse(completableFuture.isDone());
sleepForMs(2000);
Assert.assertTrue(completableFuture.isDone());
}
note that completableFuture.join()
makes the thread running the Future to join the main thread and thus you will get the exception.
Upvotes: 1
Reputation: 262
If you want to run some background task asynchronously and don’t want to return anything from the task, then you can use CompletableFuture.runAsync() method. It takes a Runnable object and returns CompletableFuture.
@Test
public void running_a_simple_asynchronous_stage(){
CompletableFuture completableFuture = CompletableFuture.runAsync(()->{
Assert.assertTrue(Thread.currentThread().isDaemon());
sleepForMs(1000);
}, service);
Assert.assertFalse(completableFuture.isDone());
sleepForMs(2000);
Assert.assertTrue(completableFuture.isDone());
}
thenApplyAsync :- There is no other thread around so thenApplyAsync () is invoked in the context of current main thread
@Test
public void asynchronously_applying_a_function_on_previous_stage(){
CompletableFuture completableFuture = CompletableFuture.completedFuture("astring").thenApplyAsync(str->{
Assert.assertFalse(Thread.currentThread().isDaemon());
sleepForMs(1000);
return str.toUpperCase();
}, service);
Assert.assertFalse(completableFuture.isDone());
Assert.assertNull(completableFuture.getNow(null));
sleepForMs(2000);
Assert.assertTrue(completableFuture.isDone());
Assert.assertEquals("ASTRING", completableFuture.getNow(null));
}
test 1 is a daemon thread and test2 is not daemon thread. Hope so you understood :(
Upvotes: 0