Multi-threading is a widespread programming and execution model that allows multiple threads to exist within the context of one process. Each of these threads can run in parallel and these thread share similar address space. Okay let's start from the very beginning.
thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system. Most times a thread exist within the process and multiple threads can exist within a single process, hence multi-threading.
I'd say a Computer Scientist would see A
Threadthe same way a Chemist would see an An
threads run concurrently and they share resources. The implementation of
threads and processes differ between operating systems, but in most cases a thread is a component of a process.
Processes are instances of programs which typically run independent from each other. For Example, if you start a Java program the operating system spawns a new
process which runs in parallel to other programs. Inside those processes we can utilize threads to execute code concurrently, so we can make the most out of the available cores of the CPU.
Unlike Threads, processes do not share resource with one another. A
process is a unit of resources, while a thread is a unit of scheduling and execution.
Creating a brand-new OS thread requires memory allocation and CPU instructions in order to set it up and also kill it down. In order to better handle the usage of a thread and also avoid the creation of new ones, the operating systems or platforms reckon with a
Thread Pool feature, which allows the application to take an already existing thread to use.
That’s a much more efficient way to handle multiple threads without dealing with its creation or destruction. Furthermore, the OSs know when a thread from the thread pool is not actively in use thus, they can automatically “skip” it during the threads’ iteration.
We'd take a look at threads as implemented from two classes in Java,
Executorsas a class in Java that abstracts most of the manual thread creation process. They are capable of running asynchronous tasks and typically manage a pool of threads, so we don't have to create new threads manually.
Executors provides convenient factory methods for creating different kinds of executor services. In the sample below we use an executor with a thread pool of size one.
The result looks similar to the above sample but when running the code you'll notice an important difference, the java process never stops!
Executors have to be stopped explicitly - otherwise they keep listening for new tasks.
ExecutorService provides two methods for that purpose:
shutdown() waits for currently running tasks to finish while
shutdownNow() interrupts all running tasks and shut the executor down immediately. This service is mostly used when working with socket connections, to facilitate asynchronous calls(Sink-Source connections).
Runnableis functional interface defining a single void no-arguments method
run(). Before starting a new thread you have to specify the code to be executed by this thread, often called the task and this is done by implementing a
Runnable. Note that, you can have as many tasks as possible.
For the example above, we utilize Java 8 lambda expressions to print the current threads name to the console. First we execute the runnable directly on the main thread before starting a new thread. See the sample outputs below.
Hello main Hello Thread-0 Done!
Hello main Done! Hello Thread-0
We have two possible outputs because due to concurrent execution we cannot predict if the runnable will be invoked before or after printing
Done. The order is non-deterministic, thus making concurrent programming a complex task in larger applications. Although Threads can also be put to sleep for a certain duration.
Like we've clearly stated earlier, A
multi-threaded program contains two or more parts that can run concurrently and each part can handle a different task at the same time making optimal use of the available resources specially when your computer has multiple CPUs.
Multi-threading extends the idea of multitasking into applications where you can subdivide specific operations within a single application into individual threads. It enables you to write in a way where multiple activities can proceed concurrently in the same program.
There are a handful of programming languages that give room for
multi-threading, and most of the languages are Object Oriented Programming languages(OOP). Languages like
C++ and even
.NET frameworks. Some other interpreted languages also made the cut, like
Ruby MRI for
Python. If you were waiting to see
Almost all well-built applications support multi-threading. Let's look at browsers. Most browsers are multi-threaded from
Chrome and many others. But today we'd talk more about
Chrome has a multi-process architecture and each process is heavily multi-threaded. The main goal is to keep the main thread (“UI” thread in the browser process) and IO thread (each process’ thread for handling IPC) responsive. This means offloading any blocking I/O or other expensive operations to other threads.
Chrome, each and every tab you open gets its own content process. Five tabs, 5 processes, one hundred tabs, 100 processes. This approach maximizes performance, but you pay a hefty penalty in memory consumption and battery life. Ever wondered why the CPU consumption for Chrome on your task manager is always high? Well, here you go.
Every chrome process has,
main threadThis thread updates the UI and runs most of Blink.
IO threadThis thread handles IPCs and network requests
- A few more
- A pool of
Chrome Compared to Firefox
Chrome creates a content process for each tab,
Firefox instead spins up to four content process threads by default. In Firefox, the first 4 tabs each use those 4 processes and additional tabs then use threads within those processes. Multiple tabs within a process share the browser engine that already exists in memory, instead of each creating their own.
Jkwery ✊🏼Sometimes, I remember that for every Chrome Tab you have open is a different process with multiple threads running on each of them. Fifty tabs, 50 processes🥴18:48 PM - 04 Feb 2021
Threads are different from the conventional multitasking process in so many ways:
- Processes are typically independent, while threads exist as subsets of a process.
- Processes carry considerably more state information than threads, whereas multiple threads within a process share process state as well as memory and other resources.
- Processes have separate address spaces, whereas threads share their address space.
- Processes interact only through system-provided inter-process communication mechanisms.
- Context switching between threads in the same process typically occurs faster than context switching between processes.
Parallelism relate to the concept were the work is distributed in multiple units, in such a way that it doesn't compromise the final product but minimizing the total execution time.
Parallel execution is the ability of two (or more) tasks to run at the very same time. While Concurrency stands for the possibility, Parallelism is the reality.
Multithreading is now an important part of modern software development. It’s supported by many programming languages and platforms and goes all the way down to the operating system. Knowing how to work with multiple threads can definitely lead developers to build better applications.