Java 4
Java 4
Why threads
• Need to handle concurrent processes
• Definition
– Single sequential flow of control within a program
• Threads are like a processes executed by a program
• Example:
– Operating System
– HotJava web browser
Multi-threading in Java Platform
• Java Application start with just one thread, called the main thread.
– This thread has the ability to create additional threads
• That second new call stack runs concurrently with the main thread
• Every java program has at least one thread called main thread
• Thread.currentThread().getName()
public NumberService() {
super();
}
public void sumNumbers(int countTo) {
for(int i=0;i<=countTo;i++) {
count =count +i;
}
• start()
– The thread moves from the new state to the runnable state.
try {
System.out.println(ch);
} catch (IOException e) {
e.printStackTrace();
}
}
The Thread Scheduler
• java.lang.Object Class
• New
– When the Thread has been instantiated
• The start() method has not been invoked on the thread.
– It is a live Thread object, but not yet a thread of execution.
– At this point, the thread is considered not alive.
• Runnable
– The state a thread is in when it’s eligible to run,
– Scheduler has not selected it to be the running thread.
– A thread first enters the runnable state when the start() method is
invoked
– A thread can also return to the runnable state after either running or
coming back from a blocked, waiting, or sleeping state.
– When the thread is in the runnable state, it is considered alive.
Thread States
• Running
– This is the state a thread is in when the thread scheduler selects it from
the runnable pool to be the currently executing process.
– A thread can transition out of a running state for several reasons,
including because “the thread scheduler felt like it.”
• Waiting/blocked/sleeping
– The thread is still alive, but is currently not eligible to run.
– A thread may be sleeping because the thread’s run code tells it to sleep
for some period of time
• Dead
• A thread is considered dead when its run() method completes.
• It may still be a viable Thread object, but it is no longer a separate
thread of execution. Once a thread is dead, it can never be brought back
to life
• A runtime exception will be thrown
Leave the running state
• sleep()
• join()
• Guaranteed to cause the current thread to stop executing until the thread it
joins with the thread it calls wait on completes.
– A thread can’t acquire the lock on the object whose method code it’s
attempting to run
The sleep() method
• Static method of Thread Class
• Can be Placed anywhere in the Code
• Throws a Checked Exception – Interrupted Exception
try {
Thread.sleep(5*60*1000); // Sleep for 5 minutes
} catch (InterruptedException ex) { }
The Join() Method
• The non-static join() method of class Thread lets one thread “join onto the
end” of another thread.
• The thread class join method waits until a thread is finished executing or
waiting for a thread to die before returning .
Joining Thread
public class TaskForJoin implements Runnable {
System.out.println("Reading");
try {
System.in.read( );
System.out.println("Thread Finished.");
}
}
Joining Thread
public class ParentThread {
System.out.println("Starting");
t.start( );
System.out.println("Joining");
Joining Thread
try {
t.join( );
ex.printStackTrace();
System.out.println("Main Finished.");
}
Synchronizing Code
• Sometimes it is desirable that only one thread at a time has access to a shared
resource.
• A lock can be associated with a shared resource. Threads gain access to a shared
resource by first acquiring the lock associated with the resource.
• one thread can hold the lock and thereby have access to the shared resource.
Synchronizing Code
Synchronizing Code
• A thread can enter a synchronized method, thus acquiring a lock, and then
immediately invoke a synchronized method on a different object, thus
acquiring that lock as well.
class TwoStrings {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie)
{
ie.printStackTrace();
}
System.out.println(str2);
}
}
Thread Synchronization
this.str1 = str1;
this.str2 = str2;
}
}
Thread Synchronization
}
}
Output- May be in Different Order
Hello there
How are you
Thank you very much
Bye,Bye
Thread Interaction
• If many threads are waiting on the same object, only one will be chosen (in
no guaranteed order) to proceed with its execution.
• This notifies all waiting threads and they start competing to get the lock. As
the lock is used and released by each thread, all of them will get into action
without a need for further notification.
• Object can have many threads waiting on it, and using notify() will affect
only one of them.
• Which one exactly is not specified and depends on the JVM implementation,
• never rely on a particular thread In cases in which there might be a lot more
waiting, the best way to do this is by using notifyAll().
Notify -Example
class BankAccount {
balance=balance+amount;
notify();
return balance;
}
Notify -Example
public synchronized double withdraw(double amount)
{
if(balance <amount) {
System.out.println("In sufficent Balance ");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
balance =balance-amount;
return balance;
}
Notify -Example
public static void main(String[] args) {
• notifyAll()
– A better option than notify()
– It sends a notification to all the threads.
– If one is not able to proceed, there is still some more threads to
do the job
Notify and notifyAll()
EXECUTOR FRAMEWORK
Executor Framework
• Released with the JDK 5 as part of java.util.concurrent package
• Thread Creation
– Has methods for creating a pool of threads to run tasks concurrently.
– Has methods for submitting tasks for execution in the thread pool
• ExecutorService
– A sub interface of Executor
– Has methods to manage lifecycle of threads
– Used for running the submitted tasks
– Has methods that produce a Future to get a result from an
asynchronous computation.
Executor Service
• Has methods to start and terminate thread.
• execute()
– Used for threads which are Runnable
• submit()
– Used for Callable threads.
• shutdown()
– Stops accepting new tasks, waits for previously submitted tasks to execute,
– Then terminates the executor.
• shutdownNow()
– Interrupts the running task and shuts down the executor immediately.
Thread Pool
• A pool of worker threads
– Executors use thread pools to execute tasks.
– Executors Utility class provides different methods to create
thread pool.
– New thread for each process without any throttling leads to the
creation of many threads.
• They occupy memory and cause wastage of resources.
Working of Executors
Types of Executors –Single Thread Executor
• newSingleThreadExecutor()
– Executor has only a single thread.
• The new task will wait in a queue until the thread is free to
execute it.
• If the thread dies due to an exception while executing a task, a
new thread is created to replace the old thread and the
subsequent tasks are executed in the new one.
ExecutorService executorService =
Executors.newSingleThreadExecutor()
Single Threaded Executor
Task
public class PrintNames {
System.out.println(str1);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str2);
}
}
Runnable
public class ExecutorPrintService implements Runnable {
ExecutorService executor =
Executors.newSingleThreadExecutor();
ExecutorPrintService tasks[] = {
new ExecutorPrintService("Idly","sambar"),
new ExecutorPrintService("Parantha","achar"),
new ExecutorPrintService("pizza","coke")};
for(int i=0;i<tasks.length;i++) {
executor.submit(tasks[i]);
}
executor.shutdown();
}
Runnable Task
public class NameManager implements Runnable {
service.submit(task1);
service.submit(task2);
task1.getList().forEach(System.out::println);
service.shutdown();
Executors.newFixedThreadPool
– Create a thread pool of fixed size,
– Executor service picks one of the available threads from the pool
and executes the task on that thread.
– Makes sure that the pool always has the specified number of
threads running.
– If any thread dies it is replaced by a new thread immediately.
– If all the threads are busy , the new tasks will wait for their turn in
a queue.
Fixed Thread Pool
Submit to Executor
public static void main(String[] args) {
ExecutorService executor =
Executors.newFixedThreadPool(poolSize);
ExecutorPrintService tasks[] = {
new ExecutorPrintService("Idly","sambar"),
new ExecutorPrintService("Parantha","achar"),
new ExecutorPrintService("pizza","coke")};
for(int i=0;i<tasks.length;i++) {
executor.submit(tasks[i]);
}
executor.shutdown();
}
Size of the Fixed Thread Pool
• Decided based on the use-case of the java program.
• It also depends on number of CPU cores
• CPU Bound
• Tasks which involves mathematical calculations.
• IO Bound
• Tasks which involve communication to other application through
network calls like database, web services
• Ideal size depends on the wait time of the IO task.
• Difference
– newSingleThreadExecutor()
• can never increase its thread pool size more than one.
– newFixedThreadPool(1)
• (1) stands for the number of threads in the pool
• can increase its thread pool size more than one at run time
– Throws un-handled Exception.
• submit
– returns a Future object to manage the task.
• call()
• Future.isDone
• mayInterruptIfRunning.
– True
• the thread that is currently executing the task will be interrupted
– False
• in-progress tasks will be allowed to complete.
• Future.isCancelled()
– To check if a task is cancelled or not.
Callable Example
public class Task implements Callable<String> {
@Override
public String call() throws Exception {
return "Hello " + message + "!";
}
}
Callable Example
public class ExecutorExample {
public static void main(String[] args) {
try {
System.out.println(result.get());
} catch (InterruptedException | ExecutionException e) {
System.out.println("Error occured while executing the submitted task");
e.printStackTrace();
}
executorService.shutdown();
}
}
Callable Example
public class FactorialCalculator implements Callable<Integer> {
private Integer number;
@Override
public Integer call() throws Exception {
int result = 1;
if ((number == 0) || (number == 1)) {
result = 1;
} else {
for (int i = 2; i <= number; i++) {
result *= i;
TimeUnit.MILLISECONDS.sleep(20);
}
}
return result;
}}
Callable Example
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
while(!future.isDone()) {
System.out.println("Task is still not done...");
try {
Thread.sleep(200);
double elapsedTimeInSec = (System.nanoTime() - startTime)/1000000000.0;
if(elapsedTimeInSec > 1) {
future.cancel(true);
}
} catch (InterruptedException e) {
e.printStackTrace(); }
Cancelling the Future
System.out.println("Task completed! Retrieving the result");
String result;
try {
result = future.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
executorService.shutdown();
}
Cancelling the Future
if(!future.isCancelled()) {
} else {
System.out.println("Task was cancelled");
}