Krushna
Krushna

Reputation: 6060

Wrapping a dead thread object in new thread object to restart it

I want to restart a thread for some use, for example in the below code.

class Ex13 implements Runnable {
    int i = 0;

    public void run() {
        System.out.println("Running " + ++i);
    }

    public static void main(String[] args) throws Exception {
        Thread th1 = new Thread(new Ex13(), "th1");
        th1.start();
            //th1.join() 
        Thread th2 = new Thread(th1);
        th2.start();
    }
}

When I'm executing the above program , some time i'm getting the output as Running 1 Running 2 and some time i'm getting only Running 1 After few run i'm getting only Running 1 as output. I'm totally surprise about this behavior. Can any one help me understand this. if I put the join() then i'm getting only Running 1.

Upvotes: 3

Views: 508

Answers (4)

Denis Tulskiy
Denis Tulskiy

Reputation: 19177

You reuse Thread instance, not Runnable. Thread overwrites its run() method to

public void run() {
    if (target != null) {
        target.run();
    }
}

Where target is the Runnable that you give to the constructor. besides that, Thread has an exit() method that is called by the VM, and this method sets target to null (the reason is this bug). So if your first thread has the chance to finish its execution, its run() method is pretty much empty. Adding th1.join() proves it.

If you want to keep some state, you need to keep reference to your Runnable instance, not the Thread. This way run() method will not be altered.

Upvotes: 2

Sinisha Mihajlovski
Sinisha Mihajlovski

Reputation: 1831

To see whats happening in the System.out.println you can also print the thread name:

Thread t = Thread.currentThread();
String name = t.getName();
System.out.println("name=" + name);

I see you call the two threads with the same runnable object, so they will both use the same "i" variable, in order for you to get Running 1 Running 2 you need to synchronize "i"

Upvotes: 0

Pavel K.
Pavel K.

Reputation: 436

I don't know why do you need this, but (please note that this code doesn't ensure that th1 is ALWAYS executed before th2, though) :

public static class Ex13 implements Runnable {
    AtomicInteger i = new AtomicInteger(0);
    CountDownLatch latch;
    Ex13(CountDownLatch latch) {
        this.latch = latch;
    }
    public void run() {
        System.out.println("Running " + i.incrementAndGet());
        latch.countDown();
    }
}

public static void main(String[] args) throws Exception {
    CountDownLatch latch = new CountDownLatch(2);
    Ex13 r = new Ex13(latch);
    Thread th1 = new Thread(r, "th1");
    th1.start();
    Thread th2 = new Thread(r);
    th2.start();
    latch.await(); // wait until both theads are executed
    System.out.println("Done");
}

Upvotes: 2

krock
krock

Reputation: 29619

You want the incrementing of i to be synchronized, i.e.

public class Ex13 implements Runnable {
    int i=0;
    public void run() {
        System.out.println("Running "+ increment());
    }
    private synchronized int increment() {
        return ++i;
    }
}

The Java Tutorial has a very nice explanation of this given a very similar scenario. The problem is that incrementing a variable is not an atomic operation. Each thread needs to read the current state of i before setting it to the new value. Restricting access to incrementing the variable to one thread at a time assures you will get consistent behavior.

Upvotes: 0

Related Questions