Friday, March 17, 2023

Multithreading in Java

Thread is a single sequence stream within a process. Each thread uses different stack of memory, but the heap space is shared. In a single processor environment, threads just run concurrently. But in a multi-processor environment, threads are spread across processors, making them run in parallel. 

Thread creation

By default, JVM creates a single thread called main thread. The user can create more Threads to improve the speed of application in three ways:

  • By extending Thread class

class A extends Thread{

    public void run(){ }

}

new A().start();

  • By implementing Runnable

This has an advantage over the previous method that the class can extend another parent class.

class B implements Runnable{

    public void run(){ }

}

new Thread(new B()).start();

  • By using the Executor framework

This uses a Thread pool where threads are already available, saving the time of creating new.

class C implements Runnable{

    public void run(){ }

}

Executors.newFixedThreadPool(3).execute(new C());

Executor can also call a Callable implemented class if a return value is expected.

In this case, submit() is used instead of execute() method.

 

Thread states

A Thread can take the following states:

·       New : A New Thread is just created

·      Runnable : The New Thread is started and running.

·      Waiting : The Thread is waiting for another Thread to finish its execution or sleeping for the specified time.

·      Blocked : The thread tries to acquire lock on object, but some other thread is already holding the lock.

·      Terminated : The Thread finished its execution or got an error.

 

Synchronized 

Multiple Threads may try to access the same resources, causing error. To avoid this, those resources can be locked using synchronization.

synchronized(this) { } // synchronized block with lock on object.

synchronized void do() { } // synchronized method with lock on the entire method.

 

Other important points

  • Every thread has a priority of scheduling which ranges from 1 to 10.
  • Invoking the run() method directly instead of start() will make the execution to run on the current stack itself rather than a new stack.
  • Thread().join() makes other threads to wait for this thread to finish.
  • Daemon Thread provides services to user threads for background supporting tasks. eg: garbage collector
  • The wait() method causes the current thread to wait until another thread invokes the notify(). The notifyAll() method wakes up all the threads that called wait( ) on the same object. All three methods can be called only from within a synchronized context.
  • The code sleep(1000) puts thread aside for exactly one second. But the code wait(1000) causes a wait of up to one second until it receives the notify() or notifyAll()
  • Deadlock describes a situation where two or more threads are blocked forever, waiting for each other.

No comments: