dendini
dendini

Reputation: 3952

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.

Upvotes: 6

Views: 29465

Answers (8)

Anand Varkey Philips
Anand Varkey Philips

Reputation: 2075

Try this, This will work as expected. Two threads printing odd and even one after another and main exiting as soon as possible.

public class YoThreD {

    static boolean isThread1 = false;

    public static synchronized boolean isThread1() {
        return isThread1 = !isThread1;
    }

    public static void main(String args[]) {

        Runnable runnableObject = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    for (int i = 1; i <= 100; i++) {
                        try {
                            if (Thread.currentThread().getName().equals("thread1")) {
                                if (isThread1()){
                                    System.out.println(Thread.currentThread().getName() + "    :   " + i);
                                }else{
                                    this.notify();
                                    this.wait();
                                }
                            } else {
                                if (!isThread1()){
                                    System.out.println(Thread.currentThread().getName() + "    :   " + i);
                                    this.notify();
                                    this.wait();
                                }
                                else{
                                }
                            }
                        } catch (Exception e) {
                        }
                    }
                }
            }
        };
        Thread thread1 = new Thread(runnableObject);
        thread1.setName("thread1");
        thread1.start();
        Thread thread2 = new Thread(runnableObject);
        thread2.setName("thread2");
        thread2.start();
        System.out.println(Thread.currentThread().getName() + "Main thread finished");
    }
}

Upvotes: 1

ankit
ankit

Reputation: 2845

You can run two thread one after other by using several ways:

  1. by using join() method. ex:

    Thread t1=new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 4; i++) {
                System.out.println("A " + i);
            }
        }
    });
    Thread t2=new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 4; i++) {
                System.out.println("B " + i);
            }
        }
    });
    
    1. by using wait() and notify() methods: ex.

`

{
public class NotiffyAllExample {

    int flag = 1;

    public static void main(String[] args) {

        NotiffyAllExample notiffyAllExample = new NotiffyAllExample();

        A1 a = new A1(notiffyAllExample);
        B1 b = new B1(notiffyAllExample);
        C1 c = new C1(notiffyAllExample);
        a.start();
        b.start();
    }
}

class A1 extends Thread {

    NotiffyAllExample notiffyAllExample;

    public A1(net.citigroup.mexico.pg.test.test.NotiffyAllExample notiffyAllExample) {
        this.notiffyAllExample = notiffyAllExample;
    }

    @Override
    public void run() {

        try {
            synchronized (notiffyAllExample) {

                for (int i = 0; i < 4; i++) {

                    while (notiffyAllExample.flag != 1) {
                        notiffyAllExample.wait();
                    }
                    System.out.print("A ");
                }
                notiffyAllExample.flag = 2;
                notiffyAllExample.notifyAll();
            }
        } catch (Exception e) {
            System.out.println("Exception 1 :" + e.getMessage());
        }

    }
}

class B1 extends Thread {

    NotiffyAllExample notiffyAllExample;

    public B1(NotiffyAllExample notiffyAllExample) {
        this.notiffyAllExample = notiffyAllExample;
    }

    @Override
    public void run() {
        try {
            synchronized (notiffyAllExample) {

                for (int i = 0; i < 4; i++) {

                    while (notiffyAllExample.flag != 2) {
                        notiffyAllExample.wait();
                    }
                    System.out.print("B ");
                }
                notiffyAllExample.flag = 1;
                notiffyAllExample.notifyAll();

            }
        } catch (Exception e) {
            System.out.println("Exception 2 :" + e.getMessage());
        }

    }
}
}

`

Upvotes: 0

darijan
darijan

Reputation: 9775

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();

Upvotes: 4

Tala
Tala

Reputation: 8928

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
    }
}

Upvotes: 4

Bitman
Bitman

Reputation: 2006

You can use SingleThreadExecutor to run one task after another Java doc

So it will put your task one after another and they will execute in sequence without blocking main thread

Upvotes: 1

Marconius
Marconius

Reputation: 703

Silly question, but if thread 2 is supposed to execute when thread 1 is done... why not just start it from thread 1?

Or maybe just have thread 1 trigger an event and the main thread can just launch the new one in response to that.

I found this example, should work for you.

Upvotes: 0

ChaseMedallion
ChaseMedallion

Reputation: 21766

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.

Upvotes: 1

Jilles van Gurp
Jilles van Gurp

Reputation: 8274

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.

Upvotes: 3

Related Questions