Threads and Executer framework (Runnable, Callable V ), Object Serialization, Externalization - Yash-777/MyWorld GitHub Wiki
Object Serialization, Externalization transient
Serialization is a mechanism to transform a graph of Java objects into an array of bytes for storage(to disk file) or transmission(across a network), then by using deserialization we can restore the graph of objects. Graphs of objects are restored correctly using a reference sharing mechanism. But before storing, check whether serialVersionUID
from input-file/network and .class file serialVersionUID
are the same. If not, throw a java.io.InvalidClassException
.
Note - It is strongly recommended that all serializable classes explicitly declare a
serialVersionUID
, since the defaultserialVersionUID
computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedserialVersionUID
conflicts during deserialization, causing deserialization to fail.
Threads
When a thread is created, a new thread of control is added to the current process. Every process has at least one thread of control, in the program's main() routine. Each thread in the process runs simultaneously, and has access to the calling process's global data. In addition each thread has its own private attributes and call stack
.
If an exception occurs in a Thread
t1
. JVM will terminate thet1
and will not carryforward the exception tomain-Deamon
thread. In order to catch the exception uset.setUncaughtExceptionHandler(h);
Variable Volatile: Volatile Keyword is applicable to variables. volatile keyword in Java guarantees that value of the volatile variable will always be read from main memory and not from Thread's local cache.
Thread CPU cache stackpost |
---|
Can we call Thread.start() multiple times?
We can call but it leads to java.lang.IllegalThreadStateException
. Its better not to call start() method multiple times.
public class ThreadTest {
public static void main(String[] args) {
ThreadCls t = new ThreadCls();
t.run(); // normal function call
t.start(); // Starts new Thread
t.start(); // java.lang.IllegalThreadStateException
}
}
class ThreadCls extends Thread {
@Override
public void run() {
while(true) {
System.out.println("---");
try {
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Threads, Multithreading, DeadLock, Join, Synchronized, volatile
Thread: Group of statements that are executed separately. Thread is a "light weight processor" which share common features of a processor.
User Defined Thread can be created in 2 ways
- Extends Thread Class
- Implements Runnable interface: As we know java doesnot support multiple inheritance. If we extends thread class the we dont have chance to extend other class. In this scenario we go for Runnable interface.
Class MyClass extends Thread, SuperClass {WRONG}
Class MyClass extends SuperClass implements Runnable
public class HelloThread extends Thread {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new HelloThread()).start();
}
}
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
Thread.sleep causes the current thread to suspend execution for a specified time period. Thread.sleep(4000); //Pause for 4 seconds
The join method allows one thread to wait for the completion of another. If t is a Thread object whose thread is currently executing,t.join();
causes the current thread to pause execution until t's thread terminates. Overloads of join allow the programmer to specify a waiting period. However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will wait exactly as long as you specify.
Volatile: Applicable to variables If we do not declare variables as volatile then every thread will have their own copy. If T1 changes the value, T2 canot access the updated value which may lead to "Data-Inconsistency" [Ex: Bank amount transfer form one account to another] Similar to Static variable(class level-Method Area) but volatile applicable of instance objects(Instance-Heap Area).
Synchronization: Threads communicate primarily by sharing access to fields and the objects reference fields refer to. applicable to Methods and Blocks. Block/Method gets executed only by 1 thread at a time. If T1 takes control of Synchronized block T2 canot access it untill T1 releases the lock. [Ex: Bank transaction form ATM,NET Banking, UPI, etc..,)
Deadlock: Deadlock describes a situation where two or more threads are blocked forever, waiting for each other.
Deadlock occurs when multiple threads need the same locks but obtain them in different order.
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1(); // Lock1, Lock2
ThreadDemo2 T2 = new ThreadDemo2(); // Lock2, Lock1
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); } catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(10); } catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Thread - Runnable(@run():void
) (vs) Callable(@call():Object
) comes into point when we are using Executer framework.
Executer frameworkstack post
Executor Interfacesjava tutorial
The java.util.concurrent package defines three executor interfaces:
- Executor, a simple interface that supports launching new tasks.
- ExecutorService, a subinterface of Executor, which adds features that help manage the life cycle, both of the individual tasks and of the executor itself.
- ScheduledExecutorService, a subinterface of ExecutorService, supports future and/or periodic execution of tasks.
ExecutorService is a subinterface of Executor
, which accepts both Runnable and Callable tasks.
Earlier Multi-Threading can be achieved using Interface Runnable
Since 1.0, but here the problem is after completing the thread task we are unable to collect the Threads information. In-order to collect the data we may use Static fields.
Example Separate threads to collect each student data.
static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
Thread t1 = new Thread( new RunnableImpl(1), "T1" );
Thread t2 = new Thread( new RunnableImpl(2), "T2" );
Thread t3 = new Thread( new RunnableImpl(3), "T3" );
multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
multiTasksData.put("T2", new ArrayList() );
multiTasksData.put("T3", new ArrayList() );
}
To resolve this problem they have introduced Callable<V>
Since 1.5 which returns a result and may throw an exception.
-
Single Abstract Method : Both Callable and Runnable interface have a single abstract method, which means they can be used in lambda expressions in java 8.
public interface Runnable { public void run(); } public interface Callable<Object> { public Object call() throws Exception; }
There are a few different ways to delegate tasks for execution to an ExecutorService.
-
execute(Runnable task):void
crates new thread but not blocks main thread or caller thread as this method return void. -
submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
crates new thread and blocks main thread when you are using future.get().
Example of using Interfaces Runnable, Callable with Executor framework.
class CallableTask implements Callable<Integer> {
private int num = 0;
public CallableTask(int num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
return num;
}
}
class RunnableTask implements Runnable {
private int num = 0;
public RunnableTask(int num) {
this.num = num;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
}
}
public class MainThread_Wait_TillWorkerThreadsComplete {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("Main Thread start...");
Instant start = java.time.Instant.now();
runnableThreads();
callableThreads();
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis());
System.out.println("Main Thread completed...");
}
public static void runnableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> f1 = executor.submit( new RunnableTask(5) );
Future<?> f2 = executor.submit( new RunnableTask(2) );
Future<?> f3 = executor.submit( new RunnableTask(1) );
// Waits until pool-thread complete, return null upon successful completion.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
public static void callableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<Integer> f1 = executor.submit( new CallableTask(5) );
Future<Integer> f2 = executor.submit( new CallableTask(2) );
Future<Integer> f3 = executor.submit( new CallableTask(1) );
// Waits until pool-thread complete, returns the result.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
}
Multi Threads - Any Exception occurs then JVM terminates only that thread.
T1.wait()
- thenT1.notify()
- Wakes up a single thread that is waiting on this object's monitor.
If no T1 is not in wait() state, If you are usingT1.notify()
then usejava.lang.IllegalMonitorStateException
class MyThread implements Runnable {
private final Object counterLock = new Object();
public static void threadSleep(int sec) {
try {
Thread.sleep(1000 * sec);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
Thread currentThread = Thread.currentThread();
String name = currentThread.getName();
synchronized (counterLock) {
System.out.println("Object Lock wait: " +name);
threadSleep(2);
}
synchronized (currentThread) {
System.out.println("Current Thread wait:" +name); //currentThread.wait(1000 * 1);
if(name.contains("0")) System.out.println("Thread-0 :: Arthmetic Excepiton:"+ 1/0);
}
}
}
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("Main Thread start...");
MyThread threadTest = new MyThread(); // Threads work on same object
Thread th = new Thread( threadTest ); th.start();
Thread th2 = new Thread( threadTest ); th2.start();
th.join();
th2.join();
System.out.println("Main Thread End.");
}
}
output:
Main Thread start...
Object Lock wait: Thread-0
Current Thread wait:Thread-0
Exception in thread "Thread-0" Object Lock wait: Thread-1
java.lang.ArithmeticException: / by zero
at com.github.yash777.Qualification.MyThread.run(ThreadTest.java:26)
at java.lang.Thread.run(Unknown Source)
Current Thread wait:Thread-1
Main Thread End.