multithreading – Programmerbay https://programmerbay.com A Tech Bay for Tech Savvy Sun, 27 Dec 2020 17:12:44 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 https://programmerbay.com/wp-content/uploads/2019/09/cropped-without-transparent-32x32.jpg multithreading – Programmerbay https://programmerbay.com 32 32 What are The Ways to Create Thread in Java ? https://programmerbay.com/ways-to-create-a-thread-in-java/ https://programmerbay.com/ways-to-create-a-thread-in-java/#respond Wed, 24 Jun 2020 06:17:10 +0000 https://programmerbay.com/?p=5956 As we know, whenever a Java program executes, a thread is created automatically which is coined as Main thread. The main thread is responsible for the creation and termination of other threads from beginning to the end of a program.

So, Java provides two approaches to create a thread.

1) By extending Thread Class
2) By Implementing Runnable Interface

Why Two Ways to create a Thread in Java ?

The reason for this is that Java doesn’t allow the concept of multiple Inheritance. That means, when one uses Thread class in the creation of threads, there would be no way to extend any other class.

To overcome this problem Runnable interface is used where a child class can inherit a class and also able to use thread functionality.

These are the following ways to create a thread in Java:

With the help of Thread Class

thread and runnable interface

A thread class allows us to manage and control any thread using its methods such as getName(),isAlive(),join()and more.

It extends object class and also implements Runnable Interface. A runnable interface that is implemented by Thread class consists of only a single method called run() method where the behavior or task of a thread is defined.

Creating a thread by extending Thread Class

Steps:

  • A class should extend the Thread Class
  • Need to override the run() method, where all tasks of a thread would be defined
  • Create the object of that class, which would act as a thread
  • call start() method, for example, thread.start()
  • start() invokes run() automatically
class MyFirstThread extends Thread{

@Override
public void run()
{
int i;
for(i=0;i<3;i++)
{
System.out.println("I am First Thread");

}

}
}
class MySecondThread extends Thread{
@Override
public void run()
{
int i;
for(i=0;i<3;i++)
{
System.out.println("I am Second Thread");

}

}
}
public class Threads1 {

public static void main(String[] args) {
MyFirstThread Thread1 = new MyFirstThread();
MySecondThread Thread2 = new MySecondThread();

Thread1.start();
Thread2.start();
}

}

 

Output:

thread output

 

With the help of Runnable interface

The runnable interface can’t call the run method directly. In order to move a thread to the Runnable state, start() method is used which invokes the run method whose definition is provided in Thread class. So, implementing only the Runnable interface wouldn’t work. Therefore, we need to create an object of a class and pass its reference as an argument to Thread class constructor explicitly.

Creating a thread by Implementing Runnable Interface

Steps:

  • A class should implement Runnable interface
  • Need to override the run() method, where all tasks of a thread would be defined
  • Create the object of that class, suppose ‘obj’
  • Create another object but, of Thread class explicitly and pass the reference of the previously created object to the constructor. For example, ‘Thread thread1 = new Thread(obj);’
  • call start() method, for example, thread.start()
  • start() invokes run() automatically
class A implements Runnable        
{
@Override
public void run()
{
int i;
for(i=0;i<5;i++)
{
System.out.println("I am child thread");
}
}
}
public class ImplementRunnable {

public static void main(String[] args) {
A obj = new A();
Thread thread1 = new Thread(obj, "child thread");
thread1.start();
}
}

Output:

run:
I am child thread
I am child thread
I am child thread
I am child thread
I am child thread

]]>
https://programmerbay.com/ways-to-create-a-thread-in-java/feed/ 0
Difference between synchronized block and synchronized method in Tabular form https://programmerbay.com/synchronized-method-vs-synchronized-block/ Thu, 05 Mar 2020 17:55:54 +0000 https://programmerbay.com/?p=6158 What is Synchronization?

Synchronization deals with asynchronous behaviour of threads. It is a way of avoiding simultaneous access of two or more threads on a particular resource.

In Java, it is implemented in form of synchronized method and synchronized blocks.

Implementing synchronization in a code helps in dealing with critical section problem, where two or more threads together try to access a resource at the same time. To overcome from this problem, Synchronization is used.

Synchronization provides the capability to control the behaviour of thread efficiently. It works by giving a monitor or lock to a particular thread.

In other words, a thread when enters in a synchronized method or block, a unique lock gets assigned to it. Carrying lock signals other threads which also want to access that resource, to wait until the first thread completes its task and release its lock.

The lock concept enables us to achieve synchronous behaviour. However, the cons of this concept is that, it increases the waiting time of thread and the total execution time takes much longer than expected. And even sometimes it raises the situation of Deadlock.

Difference between Synchronized Method and Synchronized Block in Tabular form

BasisSynchronized MethodSynchronized Block
Lock Either Object level or Class level On any object ( specified in parameter)
Scope On entire functionality, comparatively has greater scopeOnly limited to some statement, comparatively has lesser scope
PerformanceLowHigh
Waiting timeHighLow
nullPointerExceptionNoYes

Synchronized Method

A method with synchronized keyword  allows only one thread at a time to let its task complete.

A thread that comes first would take the lock  and perform its time, meanwhile other thread would wait for first thread to complete its task.

Synchronized Block

 A Block with synchronized keyword allows only one thread at a time to let its task complete.

However, it follows the same concept as a synchronized method but it has limited scope as compared to the method.

The block itself is followed with an argument wrapping reference of an object.
It comes handy when less number of statements require to be synchronized.

Java program to demonstrate the working of synchronized method and synchronized block ?

Program:

class SynchronizationExample implements Runnable{
@Override
public void run() {
incrementMe();
unSynchronizedShowMe();
}
synchronized void incrementMe() {
for (int i = 0; i <= 7; i++) {
System. out .println(Thread.currentThread().getName() + " is printing : " +
i);
}
}
void unSynchronizedShowMe()
{
System. out .println("unSynchronized : "+Thread.currentThread().getName());
synchronized (this)
{
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 0; i<5;i++)
System. out .println("printing from synchronized block :
"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
SynchronizationExample obj = new SynchronizationExample();
Thread threadOne = new Thread(obj,"Child One");
Thread threadtwo = new Thread(obj,"Child two");
threadOne.start();
threadtwo.start();
}
}

Output:

method


Key Differences

  • A synchronized method provides a lock corresponding to object-level or Class level ( i.e class level means static method ), whereas, synchronized block provides a lock on any object depending on the parameter.
  • A synchronized method imposes lock on entire functionality of the respective method, while the synchronized block is used to lock a lesser number of consecutive statements ( Critical section area).
  • Since, the synchronized method provides a lock on current instance otherwise class level, therefore,  nullPointerException can’t be expected. On the other hand, if the parameter evaluated as null, then there would be likely a nullPointerException occurred.
  • Synchronized block boosts the performance of a respective program as it is intended to use on an only certain part of the program, rather than the entire method. Whereas the synchronized method locks entire functionality even though, some part of code has nothing to do with write or update.
  • Since, performance has an indirect relation with waiting time. In other words, the synchronized method increases the waiting time, whereas synchronized block has an advantage over the method as its scope is limited and smaller than the method.

]]>
Difference between join() and yield() in Multithreading https://programmerbay.com/difference-between-join-and-yield-mulithreading/ https://programmerbay.com/difference-between-join-and-yield-mulithreading/#respond Thu, 27 Feb 2020 13:12:45 +0000 https://programmerbay.com/?p=6149 Difference between join() and yield() in Tabular form

Join MethodYield Method
It ensures a calling thread to get terminated first and then after further execution is proceeded by other thread instanceIt simply makes other threads having same priority to do their task
It puts other threads to suspended state, till the thread on which the join() call is finishedIt moves a thread from running to runnable
It allows us to provide threshold time It doesn't, totally depends on thread Schedular
Priority doesn't matterApplies on same priority thread

Join() Method

Join method ensures termination or completion of a thread on which it is called. So, that other threads can join the calling thread as and when it dies.

The statement after the join() won’t be executed by current thread instance until the thread on which it is invoked finishes its task. However, it is also possible to mention maximum time to which extent to wait.

Java program Example:

class ThreadExample extends Thread{
    @Override
    public void run() {
        System.out.println("Child thread is printing");
       for(int i=0;i<10;i++)
       {
           System.out.println(i);
       }
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
ThreadExample thread1 = new ThreadExample();
thread1.start();

        thread1.join();
        System.out.println("I will wait for child thread to join me");
        System.out.println("Now Main thread is executing");
    }
}

Output

Child thread is printing
0
1
2
3
4
5
6
7
8
9
I will wait for child thread to join me
Now Main thread is executing

 

yield() Method

Yield method simply let other threads of same priority of the calling thread to finish their task.

In other words, It tells the thread scheduler that the thread who actually called the yield() is willing to wait and allow other threads having same priority to execute their task.

Java program Example:

class ThreadExample extends Thread{
    @Override
    public void run() {


       for(int i=0;i<10;i++)
       {
           yield();
           System.out.println("I am child "+Thread.currentThread().getPriority());
       }

    }
}
public class Main {

    public static void main(String[] args) {
ThreadExample thread1 = new ThreadExample();
thread1.start();

System.out.println(" Main thread is executing");
        for(int i=0;i<10;i++)
        {

            System.out.println("I am Main "+Thread.currentThread().getPriority());
        }
    }
}

Output:

Main thread is executing
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5
 I am Main 5
 I am child 5

 

]]>
https://programmerbay.com/difference-between-join-and-yield-mulithreading/feed/ 0
What are the important Thread Class Methods? https://programmerbay.com/what-are-the-important-thread-class-methods/ https://programmerbay.com/what-are-the-important-thread-class-methods/#respond Thu, 27 Feb 2020 12:31:49 +0000 https://programmerbay.com/?p=6142 As we previously discussed,  Java can create a thread in two ways, either through Thread class or Runnable Interface.

Since, Runnable Interface consists a single method called run() and it is implemented by Thread Class itself. Even though if one creates a thread using Runnable, still requires to make an instance of the Thread class and the object required to pass to it as an argument.

Why we need to create Thread class object even after implementing Runnable Interface?

The answers is, start() method which is responsible for thread execution ( internally calling run method), registering a thread to thread Scheduler and more.

And this start() method resides in Thread class. So, this is the reason, why we need to create a Thread object separately.

Apart from start(), Thread class supports a bunch of useful methods that not only control thread’s behaviour but also in acquiring information of a thread such as thread name,its priority and more

Some of the important and mostly used thread class methods are discussed here

  • wait()
  • sleep()
  • yield()
  • start()
  • isAlive()
  • join()
  • getName()
  • getPriority()
  • notify()

 

sleep()

  • Sleep method puts a thread to sleep
  • It takes milliseconds and nanoseconds as its argument
  • A thread sleeps for specified seconds mentioned in form of parameters
  • When it comes to synchronization, a thread which calls the method never release its lock or monitor
  • It throws interruptedException
  • Syntax:
    • Thread.sleep(long millisec)
    • Thread.sleep(long millisec, int nanosec)

Program:

class ThreadExample extends Thread{
    @Override
    public void run() {
        System.out.println("Child thread is about to sleep");
        try {
            sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("I am child Thread ");
    }
}
public class Main {

    public static void main(String[] args) {
ThreadExample thread1 = new ThreadExample();
thread1.start();
        System.out.println("I am Main Thread ");
    }
}

Output:

Child thread is about to sleep
I am Main Thread 
I am child Thread

join()

  • Join method puts a thread to wait for calling thread to complete its execution
  • It takes milliseconds and nanoseconds as its argument
  • It provides three types of argument variation, no argument, single and two arguments
  • It ensures a thread termination on which it calls on
  • For example, thread1.join(), it means waits for thread1 to finish
  • Additional feature is, one can mention, threshold time to which extent to wait
  • It throws interruptedException
  • Syntax:
    • this.join()
    • this.join(long millisec)
    • this.join(long millisec, int nanosec)

Program:

class ThreadExample extends Thread{
    @Override
    public void run() {
        System.out.println("Child thread is printing");
       for(int i=0;i<10;i++)
       {
           System.out.println(i);
       }
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
ThreadExample thread1 = new ThreadExample();
thread1.start();

        thread1.join();
        System.out.println("I will wait for child thread to join me");
        System.out.println("Now Main thread is executing");
    }
}

Output:

Child thread is printing
0
1
2
3
4
5
6
7
8
9
I will wait for child thread to join me
Now Main thread is executing

 

yield()

  • yield method makes a thread to wait and give a chance to other threads to complete their tasks having same priority
  • It signals thread scheduler that the thread wants to allow other threads to execute themselves
  •  It takes no argument
  • No thread having same priority means it won’t give chance to low priority threads anyway
  • Syntax
    • Thread.yield()

Program:

class ThreadExample extends Thread{
    @Override
    public void run() {


       for(int i=0;i<10;i++)
       {
           yield();
           System.out.println("I am child "+Thread.currentThread().getPriority());
       }

    }
}
public class Main {

    public static void main(String[] args) {
ThreadExample thread1 = new ThreadExample();
thread1.start();

System.out.println(" Main thread is executing");
        for(int i=0;i<10;i++)
        {

            System.out.println("I am Main "+Thread.currentThread().getPriority());
        }
    }
}

Output:

 Main thread is executing
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5
I am Main 5
I am child 5

 

Wait() & Notify()

wait() and notify() are two companion methods that work together with the aim of providing more control over threads. They provide a way to achieve inter thread communication. These methods reside under Object class.

As name suggest,

  • wait method makes current executing thread to go in suspended state whereas, notify method invokes immediate waiting thread to carry out its task again
  • wait method puts a thread to sleep and release the its lock, so that other can acquire it
  • wait method comes into play where synchronisation exist

Program:

class WaitExample extends Thread
{
 @Override
 public void run() {
 print();
 }
 synchronized void print()
 {
 System.out.println("THis is child ");
 notify();
 }
}
public class Main {
 public static void main(String[] args) {
 WaitExample thread = new WaitExample();
 thread.start();
 synchronized (thread)
 {
 System.out.println("I am in synchronised :");
 try {
 thread.wait();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("I am in invoked :");
 }

Output:

anotherone

isAlive()

  • isAlive is a boolean method to check whether a thread is running or not
  • It checks on calling thread, if it returns true, then thread is currently running otherwise terminated
  • It is an alternate to join() method

Program:

class ThreadExample extends Thread{
    @Override
    public void run() {


       for(int i=0;i<10;i++)
       {
           System.out.println("I am child ");
       }

    }
}
public class Main {

    public static void main(String[] args) {
ThreadExample thread1 = new ThreadExample();
thread1.start();
System.out.println("Child thread is running or not :"+thread1.isAlive());
    }
}

Output:

I am child 
I am child 
I am child 
I am child 
I am child 
I am child 
I am child 
I am child 
I am child 
I am child 
Child thread is running or not :true

start(), getName() or getPriority()

start():  start() method which is responsible for thread execution ( internally calling run method), registering a thread to thread Scheduler and more.

getName(): It is used to get the name of a thread

getPriority(): It is used to get the priority of a thread

class ThreadExample extends Thread{
    @Override
    public void run() {

System.out.println("This child");
System.out.println("Name : "+ Thread.currentThread().getName());
        System.out.println("Priority : "+ Thread.currentThread().getPriority());

    }
}
public class Main {

    public static void main(String[] args) {
ThreadExample thread1 = new ThreadExample();
thread1.start();
System.out.println("Child thread is running or not :"+thread1.isAlive());
    }
}

Output:

This child
Child thread is running or not :true
Name : Thread-0
Priority : 5

 

Similarly,

setPriority(): to set a thread priority

setName(): to set a thread name

]]>
https://programmerbay.com/what-are-the-important-thread-class-methods/feed/ 0
Difference Between Process Based Multitasking and Thread Based Multitasking https://programmerbay.com/difference-between-process-based-multitasking-and-thread-based-multitasking/ https://programmerbay.com/difference-between-process-based-multitasking-and-thread-based-multitasking/#respond Sat, 25 Jan 2020 17:45:03 +0000 https://programmerbay.com/?p=5933 Java has multithreading programming feature which is nothing but a form of multitasking. Multitasking enables a system to perform multiple tasks simultaneously.

The main aim of this concept is to reduce the response time and increase the throughput of a processor.

It is done by allocating a small slice of CPU time to each process and switching back and forth among these concurrently running processes, to create the illusion of parallel execution.

Multitasking can be classified into two types :

  • Process-based multitasking
  • Thread-based multitasking

multithreading and multitasking

Difference between Process-based multitasking and Thread based multitasking?

Basis Process Based MultitaskingThread Based Multitasking
DefinitionExecuting two or more programs concurrentlyExecuting two or more threads simultaneously
Smallest UnitProgramThread
OverheadHighLow
Address spaceEvery program has its own address spaceEvery thread shares a same address space
Context switching CostHighLow
Interprocess communicationlimited and expensiveInexpensive
Also KnownHeavyweight processLighweight process
Best suitableOS levelProgrammatic level
ExampleExecuting MP3 player, text editor, and Browsing concurrentlyPrinting documents as well keep editing on a text editor

Key Differences

Definition:

Process-based multitasking enables a system to execute two or more programs concurrently, whereas Thread based multitasking enables a program to carry out two or more tasks in form of threads simultaneously.

Smallest unit:

In process-based multitasking, a program is the smallest unit that can be executed independently

In thread-based multitasking, a thread is the smallest unit that can be executed independently

Overhead:

Process-based multitasking puts more overhead than thread-based multitasking.
A thread is a lightweight process, therefore thread-based multitasking puts less overhead than process-based multitasking.

Address space:

A process performs heavy tasks and takes up a separate address space
A thread performs light tasks and shares the same address space with other threads belong to the same program

Communication:

Interprocess communication is limited and expensive in Process-based multitasking, whereas
Interthread communication is inexpensive in thread-based multitasking.

Context switching;

In the case of process-based multitasking, context switching from one process to another costs high.

In case of a thread, context switching from one thread to another cost low.

Example:

Using process-based multitasking, multiple programs such as MP3 player, text editor, and Browsing are together executed parallelly.

Using thread-based multitasking, multiple tasks of a single program such as compiler in which compiling and opening another file at the same time can be done together with the help of two threads.

Process

A process is a program in execution. Each process has its own address space, program counter, data section, stack and register set.

Thread

A Thread is an independent dispatchable code that has a unique path of execution. Each thread has its own Program counter, stack and register set despite all share same address space.

]]>
https://programmerbay.com/difference-between-process-based-multitasking-and-thread-based-multitasking/feed/ 0
Explain Lifecycle of a thread in Java? https://programmerbay.com/explain-lifecycle-of-a-thread-in-java/ https://programmerbay.com/explain-lifecycle-of-a-thread-in-java/#respond Sat, 25 Jan 2020 07:26:25 +0000 https://programmerbay.com/?p=5974 Thread lifecycle in Java

A thread goes through various states after its creation.  It involves runnable, running, blocked and terminated. These are the following states:-

final thread lifecycle

New

At the time, when a thread object is defined, it is said to be born and ready to execute. It begins its life from this state. A thread can be created using the Thread class and Runnable interface.

Thread thread1 = new Thread() // using Thread class

From this state, it ready to move to a runnable state by calling the start() method.

Runnable

It is the state where a thread may start executing at any point of time. Until it gets the CPU, it waits with already waiting thread queue. The thread having the highest priority would get the CPU first and if all are having the same priority, then they would run in first-in,first-out fashion.
It is also possible to invoke a particular thread among the same priorities using yield() method.

Running

It means CPU time has been allocated to the thread and it is now executing and performing its assigned task.
From this state, it can jump to suspended state, blocked state and also to the terminated state.

Blocked

A thread ends up with this state when it waits for some resources required for completing its task or for other threads to perform its job first. sleep() and wait() are some methods that put down a thread to the blocked state. It is possible that the thread can send to a runnable state again.

Suppose, it issues Input/Output request to CPU, the CPU immediately puts the thread to a blocked state until the request fulfills.

Terminated State

This is the last stage of thread lifecycle. When a thread finishes its task, it goes to the terminated state. It is also possible that a thread is forced to kill due to some error or event.

]]>
https://programmerbay.com/explain-lifecycle-of-a-thread-in-java/feed/ 0
Difference Between Multitasking And Multithreading in Java https://programmerbay.com/difference-between-multitasking-and-multithreading/ https://programmerbay.com/difference-between-multitasking-and-multithreading/#respond Sun, 25 Aug 2019 09:03:10 +0000 https://www.programmerbay.com/?p=2643 In programming, Multitasking and multithreading are two approaches used to reduce the response time and increase the throughput of overall program.

The main difference between them is, one involves execution of multiple processes simultaneously and other one associates with execution of multiple threads of a process concurrently.

Difference Between Multitasking And Multithreading in Java

MultitaskingMultithreading
CPU executes two or more processes at the same timeCPU executes various threads of a particular process simultaneously
It involves switching between various processes concurrentlyIt involves switching between various threads of a single process concurrently
Each and every process gets definite resources and a separate memory spaceThreads share the same resource and memory space which is occupied for that very process
It is slower than multithreading as it puts overhead over CPUIt is faster than multitasking as it don't put much overhead over CPU

Key differences

  1. GENERAL

In case of multitasking, the system can perform or execute various activities or programs at the same time, by switching frequently between various tasks that are provided by the user.

In case of multithreading, the system can pay attention or execute the various threads of a particular process simultaneously, which makes the process run more efficiently.

  1. NATURE OF SWITCHING

In case of multitasking, the switching is performed by the CPU and is performed by rapidly switching between various processes in the time which allotted to each process or program by the CPU.

In case of multithreading, the switching is also performed by the CPU and is performed between the threads of a particular process by switching seamlessly and simultaneously.

  1. RESOURCE AND MEMORY

In case of multitasking, the process which needs to be executed by the CPU has to be provided with a definitive resource and allocated to a particular memory.

In case of multithreading, the various threads actually share the memory which has been allotted to the complete process beforehand and also share the resources which were reserved for that very process.

4. MULTI PROCESSING

When we talk about Multitasking, then multiprocessing happens to be a part of Multitasking.

But, when we talk about multithreading, then multiprocessing is not a part of the multithreading process.

5. HIERARCHY

If we talk about hierarchy, then the Multitasking phenomenon is above or the parent element for the multithreading phenomenon.

When we discuss the term, Multithreading then this must be kept in mind that it is a subpart of the Multitasking phenomenon.

6. COSTLIER

The Multitasking activities are more costlier than the Multithreading ones because the hardware dependence is more for the multitasking phenomenon which directly increases the cost for efficient performance.

The Multithreading activities are less costlier than Multitasking, this is because these are based on scheduling which is completely based on the software front and can be customized for almost all scenarios.

 

Multitasking:

When a machine or computer performs a variety of activities such as tasks, programs, etc. simultaneously then, this is termed as Multitasking. Multitasking is performed by allocating small slice of CPU time to each process and switching them back and forth to create the illusion of parallel execution.

multitasking

In other words, a CPU performs activities for a particular duration and then again changes. This process is so rapid that the user cannot tell any difference.

Each tasks uses memory and other resources. Therefore, multiple tasks put overhead on CPU and if there are too many tasks in execution , the speed of the system gradually slows down.

 

Multithreading:

A thread is the smallest form of a process and a process can have a varied range of threads.

multithreading

The process of executing multiple threads simultaneously is known as multithreading. It can be viewed as multitasking at programmatic level. It aims at reducing the execution time of a program and helps in obtaining efficient program

It can be used in a various scenario such as maintaining the responsiveness of application in the long run, parallel execution of two different tasks, handling client’s request in case of the Web application and more.

 

]]>
https://programmerbay.com/difference-between-multitasking-and-multithreading/feed/ 0