Friday 15 May 2015

Scheduling and Thread Priority

 You may be wondering how any software system can be truly threaded when running on a machine with a single CPU. If there is only one physical CPU in a computer system, it's impossible for more than one machine code instruction to be executed at a time. This means that no matter how hard you try to rationalize the behavior of a multithreaded system, only one thread is really being executed at a particular time. The reality is that multithreading on a single CPU system, like the systems most of us use, is at best a good illusion. The good news is that the illusion works so well most of the time that we feel pretty comfortable in the thought that multiple threads are really running in parallel.


Note
Incidentally, this same rule applies to multiprocessing systems involving a single CPU. Even though it may look as though you're downloading a file and playing a game in parallel, under the hood the CPU is busy juggling the execution of each process.

How It Works

The illusion of parallel thread execution on a system with a single CPU is often managed by giving each thread an opportunity to execute a little bit of code at regular intervals. This approach is known as timeslicing, which refers to the way each thread gets a little of the CPU's time to execute code. When you speed up this whole scenario to millions of instructions per second, the whole effect of parallel execution comes across pretty well. The general task of managing and executing multiple threads in an environment such as this is known as scheduling. So far, I've described the most basic form of timesliced scheduling, where every thread is given equal access to the processor in small increments. In reality, this turns out not to be the best approach to managing thread execution.
Undoubtedly, there are going to be situations where you would like some threads to get more of the CPU's attention than others. To accommodate this reality, most threaded systems employ some type of prioritization to allow threads to execute at different priority levels. Java employs a type of scheduling known as fixed priority scheduling, which schedules thread execution based on the relative priorities between threads. It works like this: each thread is assigned a relative priority level, which determines the order in which it receives access to the CPU. High-priority threads are given first rights to the CPU, while low-priority threads are left to execute when the CPU is idle.
One interesting thing about Java's approach to scheduling is that it doesn't employ timeslicing. In other words, the currently executing thread gets to enjoy the complete control of the CPU until it yields control to other threads. Lower-priority threads must simply wait until high-priority threads give them a chance to execute. Threads with the same priority level are given access to the CPU one after the next. 


Note
The Java runtime system itself could be merely a single process within a timesliced multiprocessing system on a particular platform. In this way, the fixed priority scheduling employed in Java applies only to Java programs executing within the Java runtime environment.

A good example of a low-priority thread is the garbage collection thread in the Java runtime system. Even though garbage collection is a very important function, it is not something you want hogging the CPU. Because the garbage collection thread is a low-priority thread, it chugs along in the background freeing up memory as the processor allows it. This may result in memory being freed a little more slowly, but it allows more time-critical threads, such as the user input handling thread, full access to the CPU. You may be wondering what happens if the CPU stays busy and the garbage collector never gets to clean up memory. Does the runtime system run out of memory and crash? No-this brings up one of the neat aspects of threads and how they work. If a high-priority thread can't access a resource it needs, such as memory, it enters a wait state until memory becomes available. When all memory is gone, all the threads running will eventually go into a wait state, thereby freeing up the CPU to execute the garbage collection thread, which in turn frees up memory. And the circle of threaded life continues!

Establishing Thread Priority

When a new thread is created, it inherits its priority from the thread that created it. The Threadclass defines three constants representing the relative priority levels for threads, which follow:
MIN_PRIORITY
NORM_PRIORITY
MAX_PRIORITY
The Java garbage collection thread has a priority of MIN_PRIORITY, whereas the system thread that manages user input events has a priority of MAX_PRIORITY. Knowing this, it's a good idea to take the middle road for most of your own threads and declare them as NORM_PRIORITY. Generally speaking, this should happen without your having to do anything special because the parent thread you are creating threads from will likely be set to NORM_PRIORITY. If, however, you want to explicitly set a thread's priority, it's pretty easy-the Thread class provides a method called setPrioritythat allows you to directly set a thread's priority.
Incidentally, the thread priority constants are actually integers that define a range of priorities. MIN_PRIORITYand MAX_PRIORITY are the lower and upper limits of the range of acceptable priority values, while NORM_PRIORITY rests squarely in the middle of the range. This means that you can offset these values to get varying priority levels. If you pass a priority value outside the legal range (MIN_PRIORITYto MAX_PRIORITY), the thread will throw an exception of type IllegalArgumentException.
Getting back to the setPrioritymethod, you can use it to set a thread's priority like this:
t.setPriority(Thread.MAX_PRIORITY);
Likewise, you can use the getPrioritymethod to retrieve a thread's priority like this:
int priority = t.getPriority();
Knowing that thread priority is a relative integer value, you can fine-tune a thread's priority by incrementing or decrementing its priority value, like this:
t.setPriority(t.getPriority() + 1);

This statement moves the thread up a little in the priority list. Of course, the extents of the priority range determine the effectiveness of this statement; in the current release of Java, MIN_PRIORITYis set to 1 and MAX_PRIORITYis set to 10. 

No comments:

Post a Comment