Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the twentytwenty domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in C:\inetpub\wwwroot\blogs\wp-includes\functions.php on line 6121
Programming – Page 4 – Club TechKnowHow!
Categories
Programming

What is Bogo Sort?

Sorting algorithms are precision-driven. Among all the effective and efficient sorting algorithms exists a highly inefficient and unconventional sorting algorithm – Bogo Sort. Instead of relying on strategic computation it relies on a game of chance. The pseudocode for bogo sort is given below:

function isSorted(arr):
    for i from 0 to length(arr) - 2:
        if arr[i] > arr[i+1]:
            return false
    return true

function bogoSort(arr):
    while not isSorted(arr):
        shuffleElements(arr)

Bogo Sort is one of the algorithms which have the worst case time complexity of Ο(∞). This is because this technique relies on the sorted array to appear magically after a random shuffle of its elements. This is like playing the game of LUDO and hoping to roll a 6 on the die just wayy more intense. The best case scenario of this sort also like other sorting techniques occurs when the given input is already sorted.

This algorithm performs best when the work for it has been already done. i.e. when it is not needed.🤦🏻

Categories
Java

Parallelism and Concurrency

Concurrency and Parallelism are both concepts which are used in multithreading. Concurrency refers to the sequential completion of small pieces of multiple tasks such that over a period of time both of them are completed. This means that at any instant ony one task is being processed or executed. The execution of these tasks is achieved by breaking them down into smalled sub-tasks. The core processing the tasks quickly switches between tasks to make it appear that the tasks are being processed simultaneously however the process is entirely sequential.

In the above given example we can see that both the tasks are broken down into smaller sub-tasks. These sub-tasks are performed such that both the tasks are completed almost together. The key point to remember here is that both the tasks start almost together and end almost together however at any point of time only one of them is being executed.

Before understanding parallelism first let us understand what is parallel execution. Parallel execution means true simultaneous execution of tasks. This usually requires separate processing units or COREs as both tasks would be processed independant of each other on separate COREs.Parallelism is a process in which a task is divided into smaller sub-tasks and these sub-tasks are executed parallel. This means the task is executed much faster however requires multiple COREs or threads to run on. This means to save on time we must provide more computational power or in order to save on computational power we must compromise on the speed.

Categories
Java

Executor Service in Java

In the previous article we saw how we can implement basic multithreading in java. However to design efficient and reliable systems using multithreading we need to understand concepts pertaining to the topic of concurrency to actually build systems which can benefit from multithreading. Multithreading at its core allows us to execute tasks simultaneously with the help of multiple threads working at the same time. So if we want to execute a lot of tasks we should be creating as many threads as possible to finish the tasks quickly right? No. Creating threads is also an expensive process for the machine to do. We need to find the right balance between having enough threads so that our tasks get executed quickly and the number of threads we are using should be efficient for that system. ExecutorService is a way for us to manage and execute concurrent tasks by using threads, making it simpler to create and control the thread execution process. Let us look at how we can achieve this.

Imagine the example of the taxis and passengers in the previous article. If we wish to drop all the arriving passengers to their hotels quicker we would have to hire more taxi drivers. Hiring too many taxi drivers is obviously an expensive task. In this if we were to hire an optimal amount of taxi drivers and a manager to manage the scheduling of the rides of the customers and handling the waiting ones then this process can be made faster and efficient in an resourceful manner. This is how a thread pool works.

ExecutorService allows us to create Thread Pools. A thread pool is a group of threads which are managed by the ExecutorService. New tasks can be submitted for their execution to the service itself. Once the tasks are submitted they are queued up in a blocking queue. The blocking queue enqueues the tasks if all the threads in the thread pool are executing existing tasks and dequeues them once a thread gets free and the thread begins to execute the task which is dequeued.

Note: To use the executor service you will have to import the concurrency package by java

import java.util.concurrent;

Fixed Thread Pool

Now if we choose to use a fixed thread pool size we need to be mindful of the size. Usually it is recommended to use a pool size equivalent to or just under the available threads for that machine. A unique possibility is that if we are performing tasks which require the threads to be in a waiting state, then we can have more threads as otherwise there will be no threads to execute new tasks if all the threads are in waiting state and resources will not be used effectively. Cases like this can be observed while using asynchronous programming.

ExecutorService myService = Executors.newFixedThreadPool(10);
    for (int i=0; i < 100; i++) {
        myService.execute(new Tasks());
    }

Cached Thread Pool

A cached thread pool is very similar to a fixed thread pool just the blocking queue is replaced by a synchronous queue. A synchronous queue can hold only one task at a time. When it recieves a new task it looks for any free threads in the thread pool. If it finds a free thread then the task is executed by that particular thread otherwise a new thread is created to execute that task. Since this may lead to the creation of a large number of threads, the newly created threads are terminated if they are found to be idle for a specific amount of time to avoid having too many threads.

ExecutorService myService = Executors.newCachedThreadPool();

Single Thread Executor

A single thread executor is a thread pool with a single thread. It fetches new tasks and executes them from the blocking queue. If the thread is terminated in the process of execution of a task it is recreated. This way there always exists one thread in the thread pool.

Handling Rejections

When all the threads are busy the new tasks are stored in the blocking queue, but the blocking queue also must have its limitations right. What would happen to a new task if all the threads are busy and the blocking queue is also full. If new thread creation is not an option then the task is rejected by the thread pool, this rejection can happen in one of four ways – Abort Policy, Discard Policy, Caller-Runs Policy and Discard Oldest Policy. Let us see how each of these handles the rejection of tasks.

    • Abort Policy: Simply throws a RejectedExecutionException.
    • Discard Policy: Discards the task.
    • Caller-Runs Policy: Executed the task on the caller’s thread itlsef.
    • Discard Oldest Policy: Discards the oldest task in the blocking queue and the new task is added to the queue.

Shutdown Initiations

We have seen how to start an ExecutorService and how it works, but how do we shut it down? Since the threads are executing the tasks wouldn’t the shutdown affect the execution of those tasks? We can shutdown an ExecutorService using the following command.

ExecutorService myService = Executors.newFixedThreadPool(15);
for (int i=0; i<50; i++) {
    myService.execute(new Task());
}

myService.shutdown();

When we use the command myService.shutdown(), it only initiates a shutdown. Which means that all the tasks being executed by the threads and all the tasks in the blocking queue will be completed first and then it will shutdown. In this duration if any new tasks are submitted to the thread pool  a RejectionExecutionException will be thrown.

List<Runnable> queuedTasks = myService.shutdownNow();

The above command is used when we want to shutdown immediately after the threads finish executing their current tasks. The tasks queued up in the blocking queue are returned as a list.

The status of the shutdown can be checked with the two commands – isShutdown() and isTerminated(). isShutdown() is used to check if the shutdown process has been initiated, however there is no way to know if the entire service has been shutdown only using isShutdown(), for that we will have to use the isTerminated() function as it is used to check if all the tasks are completed and hence the service has been shutdown.

// returns true if the shutdown has been initiated.
myService.isShutdown();

// returns true if all the tasks are completed, including the queues ones.
myService.isTerminated();

 

Categories
Java

Synchronization in Java

Synchronization allows for only one thread to access a piece of code or an object at any given moment. This prevents simultaneous requests to access the data by multiple threads. It is a mechanism put in place to control access to te resources which are shared among all the threads. This is done to ensure accuracy of the processes being carried out by threads and so that they dont interfere with each other or also otherwise known as interleaving, all this can lead to the data being corrupted.

Let us try to understand this using an example. Consider there exists a library a the TeckKnowHow Club. Members of the club can borrow books which they find interesting and return them once they have finished reading them. Now considering this library is multithreaded and different threads handle the borrowing and returning of books by various members of the club, it is possible that two threads try to borrow the same book for different users.

This may lead to inconsistencies in the book status and also not make for a very reliable system. In such a case synchronization needs to be introduced to tackle this issue. In simple words synchronization is used to avoid thread interference and concurrency issues.

Thread intereference: When two or more threads try to read/write to/from a single or multiple shared resources, it may lead to unpredictable and incorrect results.
Concurrency issues: When multiple threads execute concurrently and their order of execution influences the result/outcome. A few basic concurrency issues are listed below :

    1. Race Condition
      When multiple threads concurrently access the same shared resource, the outcome depends on the order of execution of the threads, hence giving us inconsistent outputs.
    2. Deadlock
      When two or more threads are waiting for each other to release a shared resource, may lead to them being unable to proceed.
    3. Starvation
      When multiple threads are waiting for each other to release the resource, it may lead to a few threads being unable to access the resource entirely

The process of gaining exclusive access over a shared resource by a particular thread is called Locking. The lock on the shared resource exists till the process being executed by the thread is completed. When a thread acquires a lock, it means that it has exclusive permission to execute the code within the locked region.
So how can you implement this concept of synchronization in code?
There are two ways in which this can be done:

    1. Using synchronization blocks.
    2. Using synchronized methods.

Synchromization Blocks

You can write certiain pieces of code inside a synchronization block, which will synchronize it for you. This method allows for more detailed control over synchronization. This is due to the synchronization being applied only to parts of code and not entire functions or methods.

synchronized (object) {
    // here object refers to the object for which the shared resources will be locked.
    // code which needs to be synchronized.
}

Synchronized Methods

An entire method can be declared synchronized by using the ‘synchronized’ keyword in the mthod declaration. This is used when we want the entire functionality of a method to be synchronized.

synchronized <return type> function name (args) {
    // functionality of the method.
}

 

Categories
Java

Multithreading in Java

Multithreading is a way for us to execute the same process across multiple threads. A thread can be understood as a small unit which executes a program/process. A process can be executed by multiple threads at the same time simultaneously, this is known as multithreading. These threads can share the same resources like memory, but they can also have their own independant resources. Threads have their own program counters, stack and even their own registers. This allows for independant processing across threads, which means that the output of a single thread is independant of other threads. This means that even if a particular thread runs into a problem or exception the processing of other threads will not be affected by it. This is a major advantage when it comes to multithreading. Let us understand this with a further example :

let us assume there is a single taxi standing outside a busy airport. Assuming that the passengers arriving use only taxis to commute to their hotels, the taxi driver will have to make successive trips to drop all the passengers to their respective hotels. This will be a very time consuming process and labour intensive on the taxi driver as he will have to drop all the passengers one after the other. This problem can be fixed by having multiple taxis available. This approach divides the load and makes the process much faster also without tiring out the drivers too much.

Multithreading therefore allows us to run several threads in parallel, taking advantage of multi-core processors to perform tasks concurrently.

Let us try to understand how multithreading can be implemented in java. There are two ways in which this can be achieved :

    1. Extending Thread in the class where multithreading is performed.
    2. Implementing the Runnable method.

Extending Thread

First we create a class and extend Thread as te name suggests, inside it we will override the run() method. Inside the run() method you should put the code for the process that you want a single thread to or each thread to perform. This can be as simple as counting from 1 to 5 or as complex as simultaneously running different data points through a machine learning model. Make sure to use a try-catch block inside the run method to handle the exceptions. Once we have defined the task for each thread we will create an object of the class in our main method and use the start() method to begin the execution of a new thread. When the start() method is called the JVM(java virtual machine) creates a new thread and invokes its run() method.

So if you want 10 threads to perform the mentioned task then you should create 10 different objects and call the start() method for each of them. This can be done simply using a for loop.

package Multithreading;
import java.util.Date;

class MultithreadingClass extends Thread {
    @Override
    public void run() {
        try{
            for(int i = 0; i < 5; i++){
                Date d = new Date();
                System.out.println("Thread " + Thread.currentThread().threadId() + " is running at : " + d);
                Thread.sleep(1000);
            }
            
        }
        catch (Exception e){
            System.out.println("Exception is caught : " + e);
        }
    }
}
public class DateTime {
    public static void main(String[] args) {
        int n = 5;
        for (int i = 0; i < n; i++) {
            MultithreadingClass object = new MultithreadingClass();
            object.start();
        }
    }
}

We can visualise the working of this in real-time even better if we use the command ‘Thread.sleep(1000)’ immediately after it performs the task in the run() method. This stops the processing of each thread for exactly 1000 milliseconds or 1 second after completing their single task.

Implementing Runnable

Since we are not extending Thread anymore we cannot call the start() method directly in our main method. Instead we will create a new Thread in the main method and pass in the object of the class that implements the Runnable Interface. Now we can call the start() method for the Thread.

package Multithreading;
import java.util.Date;

class MultithreadingClass implements Runnable {
    @Override
    public void run() {
        try{
            for(int i = 0; i < 5; i++){
                Date d = new Date();
                System.out.println("Thread " + Thread.currentThread().threadId() + " is running at : " + d);
                Thread.sleep(1000);
            }
            
        }
        catch (Exception e){
            System.out.println("Exception is caught : " + e);
        }
    }
}
public class DateTime {
    public static void main(String[] args) {
        int n = 5;
        for (int i = 0; i < n; i++) {
            MultithreadingClass object = new MultithreadingClass();
            Thread T = new Thread(object);
            T.start();
        }
    }
}

The output for the above code looks like this

From this we can clearly see that 5 threads are working simultaneously, i.e. Threads – 29, 30, 31, 32, and 33. Note that in each cycle the threads are not printing in the same order, which means some threads finish the same task faster than others and it cannot be predicted which thread will be faster as it is random and it depends on the systems resource allocation.