Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for a thread that spawns it's own thread?

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?

like image 450
Aequitas Avatar asked Jan 29 '16 02:01

Aequitas


People also ask

How do you wait on threads?

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.

Is there a way to keep a thread from executing until another thread is finished running?

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.

How many threads can be spawned?

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.


2 Answers

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:

  • Make 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.
  • Return the newly created thread from 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.

like image 197
Dolda2000 Avatar answered Oct 18 '22 03:10

Dolda2000


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.

like image 3
Ravindra babu Avatar answered Oct 18 '22 03:10

Ravindra babu