JAVA Thread Scheduling

 

 

Features :

  1. The JVM schedules using a preemptive , priority – based scheduling algorithm.
  2. All Java threads have a priority and the thread with he highest priority is scheduled to run by the JVM.
  3. In case two threads have the same priority a FIFO ordering is followed.

 

 

A different thread is invoked to run in case one of the following events occur:

1.The currently running thread exits the Runnable state ie either blocks or terminates.

2. A thread with a higher priority than the thread currently running enters the Runnable state. The lower priority thread is preempted and the higher priority thread is scheduled to run.

 

Time Slicing is dependent on the implementation.

A thread can voluntarily yield control through the yield() method. Whenever a thread yeilds control of the CPU another thread of the same priority is scheduled to run. A thread voluntarily yielding control of the CPU is called Cooperative Multitasking.

 

Thread Priorities

JVM selects to run a Runnable thread with the highest priority.

All Java threads have a priority in the range 1-10.

Top priority is 10, lowest priority is 1.Normal

priority ie. priority by default is 5.

Thread.MIN_PRIORITY - minimum thread priority

Thread.MAX_PRIORITY - maximum thread priority

Thread.NORM_PRIORITY - maximum thread priority

 

Whenever a new Java thread is created it has the same priority as the thread which created it.

Thread priority can be changed by the setpriority() method.

 

Java Based Round-Robin Scheduler

(An example)

public class Scheduler extends Thread

{

public Scheduler(){

timeSlice = DEFAULT_TIME_SLICE;

queue = new Circularlist();

}

public Scheduler(int quantum){

timeSlice = quantum;

queue = new Circularlist();

}

public addThread(Thread t) {

t.setPriority(2);

queue.additem(t);

}

private void schedulerSleep() {

try{

Thread.sleep(timeSlice );

} catch (InterruptedException e){};

}

 

 

public void run(){

Thread current;

This.setpriority(6);

While (true) {

// get the next thread

current = (Thread)qeue.getnext();

if ( (current != null) && (current.isAlive()) ){

current.setPriority(4);

schedulerSleep();

current.setPriority(2)

}

}

}

private CircularList queue;

private int timeSlice;

private static final int DEFAULT_TIME_SLICE = 1000;

}

 

public class TesScheduler

{

public static void main()String args[]) {

Thread.currentThread().setpriority(Thread.Max_Priority);

Schedular CPUSchedular = new Scheduler ();

CPUSchedular.start()

 

TestThread t1 = new TestThread("Thread 1");

t1.start()

CpuSchedular.addThread(t1);

TestThread t2 = new TestThread("Thread 2");

t2.start()

CpuSchedular.addThread(t2);

TestThread t3 = new TestThread("Thread 1");

t3.start()

CpuSchedular.addThread(t3);

}

}

Java Synchronization

Every object in Java has a single lock associated with it. This lock is not used ordinarily.

When a method is declared as SYNCHRONIZED ,calling the method requires acquiring the lock for the object.

When the lock is owned by a different thread the thread blocks and is put into the entry set of the object’s lock.

 

Example:

public synchronized void enter(Object item){

while (count == BUFFER_SIZE)

Thread.yeild();

++count;

buffer[in] = item;

in = (in+1) % BUFFER_SIZE;

}

public synchronized void remove (){

Object item;

while (count == 0)

Thread.yeild();

--count;

item = buffer[out]

out = (out+1) % BUFFER_SIZE;

return item

}

 

 

 

WAIT() & NOTIFY()

When a thread calls the wait() method:

  1. The thread releases the lock for the object.
  2. The state of the thread is set to blocked.
  3. The Thread is placed in the wait set for the object

 

When a thread calls the notify() method:

1. An arbitrary thread is picked from the list of threads in the wait set.

  1. Moves the selected thread from the wait set to the entry set.
  2. Sets the state of the selected thread from blocked to runnable.

 

Examples of Wait() and Notify()

public synchronized void enter(Object item){

while (count == BUFFER_SIZE){

try{

wait();

}

catch (InterruptedException e) {}

 

}

// add an item to the buffer

++count;

buffer[in] = item;

in = (in+1) % BUFFER_SIZE;

notify();

}

 

 

 

public synchronized void remove(Object item){

while (count == 0){

try{

wait();

}

catch (InterruptedException e) {}

 

}

// remove an item to the buffer

--count;

item = buffer[out];

out = (out+1) % BUFFER_SIZE;

notify();

return item;

}

 

Block Synchronization in Java

Instead of synchronizing entire methods in Java one can also synchronize a part of the method .

 

 

 

Synchronization Rules

Given in the Textbook

 

 

Thread Scheduling

This question is based on Section 6.7 of the text book. Before you begin, please read though Sec 6.7 completely and make sure you understand the notion of priorities and how the JVM schedules threads.

Section 6.7.3 provides sample code for implementing a round-robin scheduler for Java threads. Using this code as a starting point, implement a MLFQ scheduler that has two queues. The priorities of threads in the two queues should be 2 and 3 respectively. Have the scheduler select a thread from the highest-priority non-empty queue, set that thread's priority to 5 and allow the thread to run for the time slice for that queue. Assume that times slice for each priority level is 2*DEFAULT_TIME_SLICE and DEFAULT_TIME_SLICE, respectively. When this time slice expires, select the next highest priority thread and repeat the process. Assume that round-robin scheduling is used at each priority level, and that a higher priority thread that wakes up does not preempt a currently executing thread. Unlike multi-level feedback queue scheduling, assume that your simple scheduler does not move threads from one priority-level to another.

Test your scheduler with three threads, one at priority level 3 and two at priority level 2. Have each thread run in a loop incrementing a counter. After every 10,000 loops, have each thread print out its id and the current value of its counter and then sleep for 5 seconds, allowing the next thread to run.

It is important to understand that the JVM has its own thread scheduler that uses priorities. Your scheduler does not replace the JVM scheduler, rather it emulates a (user-level) scheduling policy using the notion of priorities. By increasing the priority of the next thread to be scheduled, your user-level sheduler helps the JVM scheduler "pick" the right thread for execution. In some sense, the JVM scheduler acts like a kernel CPU scheduler that we learnt in class, while your scheduler acts like a user-level scheduler in a threads library.

Threads and Semaphores
Using Java semaphores described in Section 7.8.6, implement reader/writer communication.


A data object is to be shared among several concurrent threads Some of the threads - Readers want only to read the content of the shared object. When a reader, reads the content of the shared object (an integer variable), it should produce the following output to the screen:

  Reader <id> reading <integer>

where <id> is the unique identifier of the Reader and <integer> is the current value of the shared integer variable.

The Writer threads want to update (i.e. to read and write) the shared object. When a writer updates the shared object (by incrementing it by 1), it should produce the following output on the screen:

  Writer <id> writing <integer>

where <id> is the unique identifier of the writer and <integer> is the new value written to the shared object.

Test your solution with multiple readers and writers. Of course, with multiple readers and writers, the output will illustrate the concurrency provided by threads.

Your code should prompt for the number of readers and the number of writers, in that order. You can assume that a valid integer is provided by the user for each of these. You should be sure that your code works for different inputs as we may test it with inputs other than what you provide in your sample output listing