I'm trying to test a method that does it's work in a separate thread, simplified it's like this:
public void methodToTest()
{
Thread thread = new Thread()
{
@Override
public void run() {
Clazz.i = 2;
}
};
thread.start();
}
In my unit test I want to test that Clazz.i == 2, but I can't do this because I think that the assert is run before the thread changes the value. I thought of using another thread to test it and then use join to wait but it still doesn't work.
SSCCE:
@Test
public void sscce() throws InterruptedException
{
Thread thread = new Thread()
{
@Override
public void run() {
methodToTest()
}
};
thread.start();
thread.join();
AssertEquals(2, Clazz.i);
}
public static class Clazz
{
public static int i = 0;
}
I think this is because the test main code creates a thread that is waiting (joined) to the 2nd thread, but the 2nd thread doesn't do the work, it creates another thread to do the work and then finishes, which continues the first thread, while the third thread does the Clazz.i = 2
after the assertion.
How can I make it so that the first thread waits for the thread that it starts as well as any threads that that thread starts?
The wait() Method Simply put, calling wait() forces the current thread to wait until some other thread invokes notify() or notifyAll() on the same object. For this, the current thread must own the object's monitor.
you can use a CountDownLatch to syncronize thread execution. As stand in the doc, a CountDownLatch allows one or more threads to wait until a set of operations being performed in other threads completes.
Each core can only run 1 thread at a time, i.e. hyperthreading is disabled. So, you can have a total maximum of 20 threads executing in parallel, one thread per CPU/core. That can mean 20 single-threaded jobs, 1 multi-threaded job with 20 threads, or anything in between.
Without a reference to the thread created in methodToTest
, you cannot, quite simply. Java provides no mechanism for finding "threads that were spawned during this particular time period" (and even if it did, it would arguably be an ugly mechanism to use).
As I see it, you have two choices:
methodToTest
wait for the thread it spawns. Of course, if you explicitly want this to be an asynchronous action, then you can't very well do that.methodToTest
, so that any callers can choose to wait for it if they so wish.It may be noted that the second choice can be formulated in a few different ways. You could, for instance, return some abstract Future
-like object rather than a thread, if you want to extend the liberty of methodToTest
to use various ways of doing asynchronous work. You could perhaps also define some global task-pool that you enforce all your asynchronous tasks to run inside, and then wait for all tasks in the pool to finish before checking the assertion. Such a task pool could take the form of an ExecutorService
, or a ThreadGroup
, or any number of other forms. They all do the same thing in the end, but may be more or less suited to your environment -- the main point being that you have to explicitly give the caller access to the newly created thread, is some manner or another.
Since your threads seems to be performing different operations, you can use CountDownLatch to solve your problem.
Declare a CountDownLatch
in main thread and pass this latch object to other threads. use await() in main thread and decrement latch in other threads.
In Main thread: ( first thread)
CountDownLatch latch = new CountDownLatch(2);
/* Create Second thread and pass the latch. Pass the same latch from second
thread to third thread when you are creating third thread */
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Pass this latch to second and third threads and use countdown in these threads
In second and third threads,
try {
// add your business logic i.e. run() method implementation
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
Have a look this article for better understanding.
ExecutorService invokeAll
() API is other preferable solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With