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.
What is a Thread?
A 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
Thread
the same way a Chemist would see an AnAtom
.
These 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.
What is 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.
Thread Pool
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.
Descriptive Programming Representations Of Threads
We'd take a look at threads as implemented from two classes in Java, Executors
and Runnable
.
-
Executors
Executors
as 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.
The class 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.
An 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).
-
Runnable
A
Runnable
is functional interface defining a single void no-arguments methodrun()
. 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 aRunnable
. 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!
Or that:
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.
Multi-threading in-depth
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 Java
, C
,C++
and even .NET
frameworks. Some other interpreted languages also made the cut, like Ruby MRI
for Ruby
and CPython
for Python
. If you were waiting to see Javascript
, well you won't because JavaScript does not support multi-threading and that's because the JavaScript
interpreter in the browser is a single thread.
Heavily Multi-threaded Applications
Almost all well-built applications support multi-threading. Let's look at browsers. Most browsers are multi-threaded from firefox
to Safari
to Chrome
and many others. But today we'd talk more about Chrome
.
Google Chrome
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.
In 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,
- A
main thread
This thread updates the UI and runs most of Blink. - An
IO thread
This thread handles IPCs and network requests - A few more
special-purpose threads
. - A pool of
general-purpose threads
.
Chrome Compared to Firefox
While 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.
Threads Vs Processes
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
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.
Conclusion
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.
Top comments (4)
Your posts are quite exceptional. Was able to gain much from this, thanks alot...
Happy to have helped
Nice post, I especially liked your in-depth part 👏
Thank you