Threads, Multi-Threading
Thread Termination
interrupt(); daemon(true);
//Example using Thread.Interrupt() method to terminate thread.
public class main{
public static void main(String[] args){
Thread thread = new Thread(new LongComputationTask(
new BigInteger(200000), new BigInteger(1000000)));
thread.start();
thread.interrupt();
}
private static class LongComputationTask implements Runnable{
private BigInteger base;
private BigInteger power;
public LongComputationTask(BingInteger base, BigInteger power){
this.base = base;
this.power = power;
}
@Override
public void run(){
System.out.println(base+"^"+power+" = "+ pow(base, power));
}
private BigInteger pow(BigInteger base, BigInteger power){
BigInteger result = BigInteger.ONE;
for(BigInteger i = BigInteger.ONE; i.compareTo(power)!=0; i.add(BigInteger.ONE)){
if(Thread.currentThread().isInterrupted()){
System.out.println("Prematurally Interrupted Computation.");
return BigInteger.ZERO;
}
result = result.multiply(base);
}
return result;
}
}
}
Daemon Thread: Background threads that do not prevent the application from exiting if the main thread terminate as we already know any non daemon thread if it is running even though main thread terminated application doesn't terminate or stop.
Daemon Threads - Scenarios
Scenario 1: Background tasks, that should not block our application from terminating.
Examples: File saving thread in a Text Editor - thread save our files every minutes
Scenario 2: Code in a worker thread is not under our control, and we do not want it to block our application from terminating.
Example: Worker thread that uses an external library
//Daemon Threads to terminate flow
/*
Here we haven't stopped app gracefully becuase we have setDaemon true at very first
*/
//Example using Thread.Interrupt() method to terminate thread.
public class main{
public static void main(String[] args){
Thread thread = new Thread(new LongComputationTask(
new BigInteger(200000), new BigInteger(1000000)));
thread.setDaemon(true);
thread.start();
thread.interrupt();
}
private static class LongComputationTask implements Runnable{
private BigInteger base;
private BigInteger power;
public LongComputationTask(BingInteger base, BigInteger power){
this.base = base;
this.power = power;
}
@Override
public void run(){
System.out.println(base+"^"+power+" = "+ pow(base, power));
}
private BigInteger pow(BigInteger base, BigInteger power){
BigInteger result = BigInteger.ONE;
for(BigInteger i = BigInteger.ONE; i.compareTo(power)!=0; i.add(BigInteger.ONE)){
if(Thread.currentThread().isInterrupted()){
System.out.println("Prematurally Interrupted Computation.");
return BigInteger.ZERO;
}
result = result.multiply(base);
}
return result;
}
}
}
Summary
- If the method does not respond to the interrupt signal by throwing the interruptedException, we need to check for that signal and handle it ourselves.
To prevent a thread from blocking our app from exiting, we set the thread to be a Daemon thread.
Thread coordination
What we learn in this lecture:
1. Threads coordination with Thread.join()
2. Case study
Specifically, we will learn how we can guarantee that a thread upon which we depend completes its work, by the time we expected. This topic is the first step for us to gain full control over other thread's execution, so that in future, we could run certain tasks in parallel and get a significant speed up, but also be able to safely and correctly aggregate the results
Thread Coordination- Why do we need it?
1. Different threads run independently.
2. Order of execution is out of our control.
scenario: 1 Thread B may finish its work before Thread A
Thread coordination - Dependency:
What if one thread depends on another thread?
Naive Solution:
Thread B runs in a loop and keeps checking if Thread A's result is ready. But this will be counterproductive and will slow down thread A
Desired Solution:
Thread B to just go to sleep and completely get out of the way and let thread A finish its work and only when thread A is done Thread B will wake up and take the already fully completed result.
To achieve desired solution we can use following methods:
public final void join();
public final void join(long millis, int nanos);
public final void join(long millis);
public class main{
public static void main(){
List<long> inputNumbers = Arrays.asList(0L, 3435L, 35464L, 4645L);
/* we want to calulate the
Utilize multithreading and to delegate calculation
of each number of factorial to different thread this way we can calculate
all the numbers factorial in parallel
*/
List<FactorialThread> threads = new ArrayList<>();
for(long inputNumber : inputNumbers){
threads.add(new FactorialThread(inputNumber));
}
for(Thread thread : threads){
thread.start();//[1st] Factorial threads started execution
}
//so below lines of code will resolve race condition between [1st] and [2nd]
for(Thread thread : threads){
thread.join();
//we can let main thread to wait for specific time
//Threads may take unreasonably long time
//Always use the thread.join() with a time limit
//Stop the thread if it's not done in time
}
Perfomance
Criteria/definintion
Performance in Multithreaded applications
Performance can be defined in many ways depending on the use case.
Multithreaded applications performance criteria:
Latency- The time to completion of a task. Measusred in times units.
Throughput- The amount of tasks completed in a given period. Measured in tasks/time unit
Latency: