Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute two threads which wait one for the other while main thread continues

How can I start two threads where thread1 executes first, thread2 starts when thread1 ends while the main method thread can continue its work without locking on the other two?

I have tried join() however it needs to be called from the thread which has to wait for the other, there's no way to do something like thread2.join(thread1); If I call for a join inside main() I therefore effectively stop execution of the main thread and not only of thread2.

I therefore tried with ExecutorService but again same problem.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Test
{
    public static void main(String args[]) throws InterruptedException
    {
        System.out.println(Thread.currentThread().getName() + " is Started");

        class TestThread extends Thread
        {
            String name;
            public TestThread(String name)
            {
                this.name = name;
            }

            @Override
            public void run()
            {
                try
                {
                    System.out.println(this + " is Started");
                    Thread.sleep(2000);
                    System.out.println(this + " is Completed");
                }
                catch (InterruptedException ex)  {  ex.printStackTrace(); }
            }

            @Override
            public String toString()  { return "Thread " + name; }
        }

        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(new TestThread("1"));

        boolean finished = executor.awaitTermination(1, TimeUnit.HOURS);

        if(finished)
        {
           //I should execute thread 2 only after thread 1 has finished
            executor.execute(new TestThread("2"));
        }

        //I should arrive here while process 1 and 2 go on with their execution
        System.out.println("Hello");
    }
}

#EDIT: Why I need this:

I need this because Thread1 copies elements from a database table into another database, thread2 has to copy a linking table which references the table copied from thread1. Consequently thread2 has to start populating its linking table only when thread1 has finished otherwise an integrity error is given by the database. Now imagine I have several threads with different priorities due to complex linking tables and you have an idea.

like image 770
dendini Avatar asked Jul 04 '13 14:07

dendini


4 Answers

The second Thread can be custom like this (takes as argument the previous thread):

public static void main(String[] a) {
    Thread first = new Thread(new Runnable() {
        @Override
        public void run() {

        }
    });

    Thread second = new MyThread(first);
    first.start();
    second.start();

    //continue executing
}

public static class MyThread extends Thread {

    private Thread predecessor;

    public MyThread(Thread predecessor) {
        this.predecessor = predecessor;
    }

    public void run() {
        if (predecessor != null && predecessor.isAlive()) {
            try {
                predecessor.join();
            } catch (InterruptedException e) {}
        }
        //do your stuff
    }
}
like image 68
Tala Avatar answered Nov 15 '22 10:11

Tala


You can use a CountDownLatch:

create it in the main thread, pass it on to both threads and call countdown on it in thread one when it exits and await it being counted down at the start of thread 2.

like image 22
Jilles van Gurp Avatar answered Nov 15 '22 11:11

Jilles van Gurp


I am pretty sure you got something wrong because this must work and it does work:

new Thread() {
    @Override
    public void run() {
        TestThread t1= new TestThread("1");
        TestThread t2= new TestThread("2");
        try {
            t1.start();
            t1.join();
            t2.start();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}.start();

The ouput is:

main is Started
Hello
Thread 1 is Started
Thread 1 is Completed
Thread 2 is Started
Thread 2 is Completed

Another option would be to extend the TestThread for the "Thread 1" to execute the work of "Thread 2" after it has been done with its own work. Something similar to this:

final TestThread t2= new TestThread("2");
TestThread t1= new TestThread("1") {
    @Override
    public void run() {
        super.run(); //finish t1 work
        t2.start();  // start t2 work
    }
};
t1.start();
like image 40
darijan Avatar answered Nov 15 '22 09:11

darijan


Why not just have thread1 be the one to start thread2?

// in main
new Thread(new Runnable() {
    @Override public void run() {
        // do thread1 work
        new Thread(new Runnable() {
              @Override public void run() { /* do thread2 work */ }
        }).start();
    }
}).start();

However, it's not at all clear why you would want to do this as opposed to just having thread1 do 100% of the background work.

like image 25
ChaseMedallion Avatar answered Nov 15 '22 11:11

ChaseMedallion