Java Concurrency : Part 2 - Manipulate Threads

After seeing how to create Threads, we'll see in this article what we can do to manipulate Threads.

When we've Threads, we can make several operations on the Threads :

  • Make the current Thread sleeping during x milliseconds
  • Wait for an other thread to complete
  • Manage the priorities of Threads and pause a thread to give an other thread the opportunity to run
  • Interrupt a thread

We'll now see how to do all these things.

First and easier, we can make a thread sleeping for a certain number of milliseconds. To do that, the Thread class has a method sleep(long millis). But this method is static, so you can only make the current Thread sleeping. You cannot choose the thread you want to make sleeping, your only choice is the current Thread so :

Thread.sleep(1000);

makes the current Thread sleep during 1000 milliseconds (1 second). But, you have to catch an exception, InterruptedException. This exception occurs if the sleeping thread is interrupted. So you have to do that :

try {
    Thread.sleep(1000);
} catch (InterruptedException e){
    e.printStackTrace();
}

But this not the good way to manage the InterruptedException. We'll see in one moment, how to deal with this exception.

If you want more precision, you can use the overloaded version of sleep that takes the number of milliseconds plus a certain number of nanoseconds to sleep. The precision of this sleep depends on the system timers and clocks.

For example, if you want to sleep 1000 milliseconds and 1000 nanoseconds (1 microsecond), you can do like that :

try {
    Thread.sleep(1000, 1000);
} catch (InterruptedException e){
    e.printStackTrace();
}

Here is a little example to test that :

public class SleepThread {
    public static void main(String[] args) {
        System.out.println("Current time millis : " + System.currentTimeMillis());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Current time millis : " + System.currentTimeMillis());

        System.out.println("Nano time : " + System.nanoTime());

        try {
            Thread.sleep(2, 5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Nano time : " + System.nanoTime());
    }
}

In my computer, this produce this result :

Current time millis : 1273959308480
Current time millis : 1273959309480
Nano time : 5878165216075
Nano time : 5878166730976

You can see that the sleep of milliseconds is very precise, but with nanoseconds the result can vary a lot. And of course, the result depends of your computer, your operating system and your configuration.

An other thing, you can do with Threads, is waiting for an other thread to die. For example, you can create five thread to compute sub result and wait for these 5 threads to finish to compute the final results based on the results of the five threads. To do that, you can use the join() method of the Thread class. This method is not static, so you can use it on any thread to wait for it to die. Like sleep() this method throws InterruptedException in the when the thread is interrupted during waiting for an other thread. So to wait on thread2, you just have to do that :

try {
    thread2.join();
} catch (InterruptedException e){
    e.printStackTrace();
}

That will make the current Thread waiting for thread2 to die. You can also add a timeout in millis, or millis + nanos, with the overloaded versions of join(), join(long millis) and join(long millis, int nanos). Here is little example that shows all that stuff :

public class JoinThread {
    public static void main(String[] args) {
        Thread thread2 = new Thread(new WaitRunnable());
        Thread thread3 = new Thread(new WaitRunnable());

        System.out.println("Current time millis : " + System.currentTimeMillis());

        thread2.start();

        try {
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Current time millis : " + System.currentTimeMillis());

        thread3.start();

        try {
            thread3.join(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Current time millis : " + System.currentTimeMillis());
    }

    private static class WaitRunnable implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        }
}

That produce this result on my computer :

Current time millis : 1274015478535
Current time millis : 1274015483538
Current time millis : 1274015484538

You can see that the first join() wait 5 seconds for the other thread and when we set a timeout, we wait only 1 seconds and return from join method.

When working with Threads, it's also possible to change the priority of a Thread. In the Java Virtual Machine, the Thread scheduler, use a priority-based scheduling. So if a Thread enter in Runnable state with a higher priority than the running Thread, the new Thread will run and the current running thread will return to Runnable state and waits for its turn. But this behavior is not guaranteed and is completely depending on the virtual machine you are working on. So, do not rely on thread priorities, just use them to improve efficiency of your program.

Normally, the priority range of Threads is an integer from 0 to 10, but some virtual machine have lower or higher ranges. To know the range of priority, you can use constants of the Thread class :

public class ThreadPriorityRange {
    public static void main(String[] args) {
        System.out.println("Minimal priority : " + Thread.MIN_PRIORITY);
        System.out.println("Maximal priority : " + Thread.MAX_PRIORITY);
        System.out.println("Norm priority : " + Thread.NORM_PRIORITY);
         }
}

On my computer, I've the most current values :

Minimal priority : 1
Maximal priority : 10
Norm priority

To set the priority of a Thread, you can use the setPriority(int priority) method of the Thread class. If you enter a value greater than the maximal priority, the maximal value will be used. If you don't specify a priority, the used priority, will be the priority of the current Thread.

An other way to works with priority is the yield() method. This method is static, so this works on the current Thread. The purpose of this method is to make the Thread going to Runnable again and to give the opportunity to other threads to get their turn. But in practice, the behavior of this method is not guaranteed. It can be implemented as a no-op on certain systems. It's not easy to test that in practice, because the results can truly depends on your computer, virtual machine and operating system. It's a good things to not use the priorities of Threads in practice.

The last thing you can do with a Thread, is to interrupt it. In Java, you have no way to force a Thread to stop, if the Thread is not well-done, it can continue its execution infinitely. But you can interrupt a Thread with the interrupt() method. This method interrupt the thread, if the thread is sleeping or joining an other Thread, an InterruptedException is thrown. You have to know that if the thread was sleeping or joining, the interrupted status of the Thread will be cleared. Namely, the method isInterrupted() will return false. A little example to demonstrate that :

public class InterruptThread {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new WaitRunnable());

        thread1.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread1.interrupt();
    }

    private static class WaitRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("Current time millis : " + System.currentTimeMillis());

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("The thread has been interrupted");
                System.out.println("The thread is interrupted : " + Thread.currentThread().isInterrupted());
            }

            System.out.println("Current time millis : " + System.currentTimeMillis());
        }
        }
}

That produce that kind of result :

Current time millis : 1274017633151

The thread has been interrupted

The thread is interrupted : false

Current time millis : 1274017634151

You can see that after one second, the second thread is interrupted and that the interrupted status has been set to false. If you are not sleeping, but making a lot of heavy actions, you can test for interrupt like that to make your thread correctly interrupts :

public class InterruptableRunnable implements Runnable {
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            //Heavy operation
        }
    }
}

Now that you know how to interrupt a thread, you can imagine, that simply catch the InterruptedException is not enough to make your thread "interrupt safe". Imagine that your thread something like that :

public class UglyRunnable implements Runnable {
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            //Heavy operation
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Other operation
        }
    }
}

And now, an other thread want to interrupt your thread while your thread is sleeping. The sleep will be interrupted, but the interrupted status will be cleared so the loop will continue. A solution to make a better thread is to interrupt again the thread after an InterruptedException :

public class BetterRunnable implements Runnable {
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            //Heavy operation
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            //Other operation
        }
    }
}

With that code, the interrupted status will be restored and the loop will be stopped after interrupt. Depending on your code, you can also add a continue statement after the interrupt() to not make operations after interrupt. In some cases, you'll also needs to make several if statements to test the interrupted status to do or not to do some operations.

So, we've now covered the main operations you can do on threads. I hope you found this article interesting.

You can download the sources of this article here : Java Concurrency Sources - Part 2

In the next article about Java Concurrency, we'll see how to synchronize code to make it Thread-safe.

Related articles

  • Java Concurrency - Part 1 : Threads
  • C++11 Concurrency - Part 1 : Start Threads
  • Java Concurrency - Part 7 : Executors and thread pools
  • Java Concurrency – Part 3 : Synchronization with intrinsic locks
  • C++11 Concurrency Tutorial - Part 3: Advanced locking and condition variables
  • C++11 Concurrency Tutorial - Part 2 : Protect shared data
  • Comments

    Comments powered by Disqus