<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Gledis' blog]]></title><description><![CDATA[Gledis' blog]]></description><link>https://gledis.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 31 Aug 2026 21:28:48 GMT</lastBuildDate><atom:link href="https://gledis.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Integrating Apache Kafka with Spring Boot]]></title><description><![CDATA[This guide walks through the process of setting up Apache Kafka in Docker and integrating it with a Spring Boot application using spring-kafka.

🐳 Step 1: Set Up Kafka with Docker
1.1 Pull the Kafka Docker Image
docker pull apache/kafka
1.2 Start a ...]]></description><link>https://gledis.hashnode.dev/integrating-apache-kafka-with-spring-boot</link><guid isPermaLink="true">https://gledis.hashnode.dev/integrating-apache-kafka-with-spring-boot</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[kafka]]></category><category><![CDATA[software development]]></category><category><![CDATA[integration]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Gledis Lami]]></dc:creator><pubDate>Tue, 03 Jun 2025 09:30:03 GMT</pubDate><content:encoded><![CDATA[<p>This guide walks through the process of setting up Apache Kafka in Docker and integrating it with a Spring Boot application using <code>spring-kafka</code>.</p>
<hr />
<h2 id="heading-step-1-set-up-kafka-with-docker">🐳 Step 1: Set Up Kafka with Docker</h2>
<h3 id="heading-11-pull-the-kafka-docker-image">1.1 Pull the Kafka Docker Image</h3>
<p><code>docker pull apache/kafka</code></p>
<h3 id="heading-12-start-a-kafka-broker">1.2 Start a Kafka Broker</h3>
<p><code>docker run -d --name broker -p 9092:9092 apache/kafka:latest</code></p>
<h3 id="heading-13-open-a-shell-in-the-broker-container">1.3 Open a Shell in the Broker Container</h3>
<p><code>docker exec --workdir /opt/kafka/bin/ -it broker sh</code></p>
<h3 id="heading-14-create-a-kafka-topic-test-topic">1.4 Create a Kafka Topic (test-topic)</h3>
<p><code>./kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-topic</code></p>
<hr />
<h2 id="heading-step-2-set-up-spring-boot-project">⚙️ Step 2: Set Up Spring Boot Project</h2>
<p>Use <a target="_blank" href="https://start.spring.io/">Spring Initializr</a> or Maven to create a Spring Boot project with the following dependencies:</p>
<h3 id="heading-21-required-dependencies">2.1 Required Dependencies</h3>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.kafka<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-kafka<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>
</code></pre>
<hr />
<h2 id="heading-step-3-configure-kafka-in-spring-boot">🔧 Step 3: Configure Kafka in Spring Boot</h2>
<p><strong>application.properties</strong></p>
<p><code>spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=my-group-id</code></p>
<hr />
<h2 id="heading-step-4-kafka-producer-setup">📨 Step 4: Kafka Producer Setup</h2>
<h3 id="heading-41-kafkaproducerconfig">4.1 KafkaProducerConfig</h3>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.kafka.producer;
<span class="hljs-keyword">import</span> org.apache.kafka.clients.producer.ProducerConfig;
<span class="hljs-keyword">import</span> org.apache.kafka.common.serialization.StringSerializer;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.DefaultKafkaProducerFactory;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.KafkaTemplate;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.ProducerFactory;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KafkaProducerConfig</span> </span>{
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ProducerFactory&lt;String, String&gt; <span class="hljs-title">producerFactory</span><span class="hljs-params">()</span> </span>{
        Map&lt;String, Object&gt; configProps = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>);
        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DefaultKafkaProducerFactory&lt;&gt;(configProps);
    }
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> KafkaTemplate&lt;String, String&gt; <span class="hljs-title">kafkaTemplate</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> KafkaTemplate&lt;&gt;(producerFactory());
    }
}
</code></pre>
<h3 id="heading-42-messageproducer">4.2 MessageProducer</h3>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.kafka.producer;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.KafkaTemplate;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;
<span class="hljs-meta">@Component</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MessageProducer</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> KafkaTemplate&lt;String, String&gt; kafkaTemplate;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendMessage</span><span class="hljs-params">(String topic, String message)</span> </span>{
        kafkaTemplate.send(topic, message);
    }
}
</code></pre>
<hr />
<h2 id="heading-step-5-kafka-consumer-setup">📥 Step 5: Kafka Consumer Setup</h2>
<h3 id="heading-51-kafkaconsumerconfig">5.1 KafkaConsumerConfig</h3>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.kafka.consumer;
<span class="hljs-keyword">import</span> org.apache.kafka.clients.consumer.ConsumerConfig;
<span class="hljs-keyword">import</span> org.apache.kafka.common.serialization.StringDeserializer;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.ConsumerFactory;
<span class="hljs-keyword">import</span> org.springframework.kafka.core.DefaultKafkaConsumerFactory;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KafkaConsumerConfig</span> </span>{
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ConsumerFactory&lt;String, String&gt; <span class="hljs-title">consumerFactory</span><span class="hljs-params">()</span> </span>{
        Map&lt;String, Object&gt; configProps = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
        configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, <span class="hljs-string">"localhost:9092"</span>);
        configProps.put(ConsumerConfig.GROUP_ID_CONFIG, <span class="hljs-string">"my-group-id"</span>);
        configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DefaultKafkaConsumerFactory&lt;&gt;(configProps);
    }
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ConcurrentKafkaListenerContainerFactory&lt;String, String&gt; <span class="hljs-title">kafkaListenerContainerFactory</span><span class="hljs-params">()</span> </span>{
        ConcurrentKafkaListenerContainerFactory&lt;String, String&gt; factory = <span class="hljs-keyword">new</span> ConcurrentKafkaListenerContainerFactory&lt;&gt;();
        factory.setConsumerFactory(consumerFactory());
        <span class="hljs-keyword">return</span> factory;
    }
}
</code></pre>
<h3 id="heading-52-messageconsumer">5.2 MessageConsumer</h3>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.kafka.consumer;
<span class="hljs-keyword">import</span> org.springframework.kafka.annotation.KafkaListener;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;
<span class="hljs-meta">@Component</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MessageConsumer</span> </span>{
    <span class="hljs-meta">@KafkaListener(topics = "test-topic", groupId = "my-group-id")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">listen</span><span class="hljs-params">(String message)</span> </span>{
        System.out.println(<span class="hljs-string">"Received message: "</span> + message);
    }
}
</code></pre>
<hr />
<h2 id="heading-step-6-rest-controller-for-testing">🌐 Step 6: REST Controller for Testing</h2>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.kafka.controller;
<span class="hljs-keyword">import</span> com.example.kafka.producer.MessageProducer;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;
<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KafkaController</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> MessageProducer messageProducer;
    <span class="hljs-meta">@PostMapping("/send")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">sendMessage</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam("message")</span> String message)</span> </span>{
        messageProducer.sendMessage(<span class="hljs-string">"test-topic"</span>, message);
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Message sent: "</span> + message;
    }
}
</code></pre>
<hr />
<h2 id="heading-testing-the-setup">✅ Testing the Setup</h2>
<ol>
<li><p><strong>Run</strong> your Spring Boot application.</p>
</li>
<li><p>Use <strong>Postman</strong> or <strong>curl</strong> to test:</p>
<p> <code>curl -X POST "http://localhost:8080/send?message=Hello_Kafka"</code></p>
</li>
<li><p>Check the application logs — the consumer should print:</p>
<p> <code>Received message: Hello_Kafka</code></p>
</li>
</ol>
<hr />
<h2 id="heading-notes">📌 Notes</h2>
<ul>
<li><p>Ensure the Kafka container is running and accessible at <code>localhost:9092</code>.</p>
</li>
<li><p>Use the same topic name (<code>test-topic</code>) in both producer and consumer.</p>
</li>
<li><p>If you want to avoid hardcoding <code>localhost:9092</code> multiple times, consider moving the config to <code>application.properties</code>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Exploring the Efficiency of Merge Sort: Concurrency vs. Traditional Approach]]></title><description><![CDATA[Introduction
In the realm of programming, sorting algorithms play a crucial role in organizing data efficiently. Traditional sorting algorithms like Merge Sort have been extensively studied and optimized for single-threaded execution. However, with t...]]></description><link>https://gledis.hashnode.dev/exploring-the-efficiency-of-merge-sort-concurrency-vs-traditional-approach</link><guid isPermaLink="true">https://gledis.hashnode.dev/exploring-the-efficiency-of-merge-sort-concurrency-vs-traditional-approach</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Java]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Gledis Lami]]></dc:creator><pubDate>Tue, 26 Mar 2024 00:28:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711409467779/5f641601-67a3-4538-8a5c-c146e6eef088.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In the realm of programming, sorting algorithms play a crucial role in organizing data efficiently. Traditional sorting algorithms like Merge Sort have been extensively studied and optimized for single-threaded execution. However, with the rise of multi-core processors, leveraging concurrency becomes essential for maximizing performance.</p>
<p>In this article, I'll delve into the world of sorting algorithms in Java, specifically Merge Sort, comparing it's traditional implementation with it's concurrent counterpart, and examining how it fares with small and large datasets.</p>
<h3 id="heading-understanding-traditional-merge-sort-algorithm">Understanding Traditional Merge Sort Algorithm</h3>
<p>Merge Sort is a divide-and-conquer algorithm that works by dividing the input array into smaller sub-arrays, sorting each sub-array recursively, and then merging the sorted sub-arrays to produce a final sorted array. The process is as follows:</p>
<ol>
<li><p><strong>Divide:</strong> The array is recursively divided into two halves until each sub-array contains only one element. This is achieved by calculating the middle index of the array and recursively calling Merge Sort on the left and right halves.</p>
</li>
<li><p><strong>Conquer:</strong> Once the sub-arrays contain only one element, the merge function is called to merge adjacent sub-arrays while maintaining the sorted order</p>
</li>
<li><p><strong>Merge:</strong> The merge function combines two sorted sub-arrays into a single sorted array. It does this by comparing elements from each sub-array and selecting the smaller (or larger) element to place into the final merged array.</p>
</li>
</ol>
<p>The following code shows an implementation of MergeSort. It's Time Complexity is: O(n log n) and Space Complexity is: O(n)</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">merge</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] array, <span class="hljs-keyword">int</span> start, <span class="hljs-keyword">int</span> mid, <span class="hljs-keyword">int</span> end)</span> </span>{
    <span class="hljs-keyword">int</span>[] leftArray = Arrays.copyOfRange(array, start, mid);
    <span class="hljs-keyword">int</span>[] rightArray = Arrays.copyOfRange(array, mid, end);
    <span class="hljs-keyword">int</span> leftIndex = <span class="hljs-number">0</span>, rightIndex = <span class="hljs-number">0</span>, arrayIndex = start;
    <span class="hljs-keyword">while</span> (leftIndex &lt; leftArray.length &amp;&amp; rightIndex &lt; rightArray.length) {
        <span class="hljs-keyword">if</span> (leftArray[leftIndex] &lt;= rightArray[rightIndex]) {
            array[arrayIndex++] = leftArray[leftIndex++];
        } <span class="hljs-keyword">else</span> {
            array[arrayIndex++] = rightArray[rightIndex++];
        }
    }
    <span class="hljs-keyword">while</span> (leftIndex &lt; leftArray.length) {
        array[arrayIndex++] = leftArray[leftIndex++];
    }
    <span class="hljs-keyword">while</span> (rightIndex &lt; rightArray.length) {
        array[arrayIndex++] = rightArray[rightIndex++];
    }
}

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">mergeSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] array, <span class="hljs-keyword">int</span> start, <span class="hljs-keyword">int</span> end)</span> </span>{
    <span class="hljs-keyword">if</span> (end - start &lt; <span class="hljs-number">2</span>) {
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">int</span> mid = (start + end) / <span class="hljs-number">2</span>;
    mergeSort(array, start, mid);
    mergeSort(array, mid, end);
    merge(array, start, mid, end);
}
</code></pre>
<hr />
<h3 id="heading-concurrent-programming">Concurrent Programming</h3>
<p>Concurrent programming in Java involves the execution of multiple tasks simultaneously, allowing for better utilization of system resources and improved performance. Key components of concurrent programming in Java include:</p>
<ul>
<li><p><strong>Threads:</strong> The smallest unit of execution within a process. Java provides built-in support for creating and managing threads through the <code>Thread</code> class or by implementing the <code>Runnable</code> interface.</p>
</li>
<li><p><strong>Executors:</strong> Provide more flexibility and control over thread management.</p>
</li>
<li><p><strong>Concurrency Utilities:</strong> Java offers us synchronized blocks, locks, atomic variables and high-level constructs like <code>CountDownLatch</code>, <code>Semaphore</code> for coordinating concurrent tasks.</p>
</li>
</ul>
<h3 id="heading-benefits-of-concurrency-in-sorting-algorithms">Benefits of Concurrency in Sorting Algorithms</h3>
<p>Concurrency can offer several advantages when applied to sorting algorithms, particularly for handling large datasets:</p>
<ul>
<li><p><strong>Parallelism:</strong> Concurrent sorting algorithms can leverage multiple threads to process different parts of the dataset simultaneously. This parallelism can lead to significant performance improvements.</p>
</li>
<li><p><strong>Scalability:</strong> Concurrency allows sorting algorithms to scale efficiently with increasing dataset sizes by distributing the workload across multiple threads.</p>
</li>
</ul>
<h3 id="heading-concurrent-merge-sort-algorithm">Concurrent Merge Sort Algorithm</h3>
<p>The difference of both algorithms is that here we split the original array into segments to achieve parallelism. Each segment is sorted concurrently by using <code>mergeSort()</code> then merged into one big array.</p>
<p>I am using a custom <code>ThreadPool</code> which starts a specific number of threads(2, 4, 8, etc) that wait for tasks to be submitted. The <code>CountDownLatch</code> helps us coordinate the completion of sorting tasks performed by multiple threads. When the array is divided into segments, we want to wait until all sorting tasks are completed before merging. The <code>CountDownLatch</code> provides a simple way to achieve this coordination.</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">concurrentMergeSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] array, ThreadPool threadPool)</span> </span>{
        <span class="hljs-keyword">int</span> length = array.length;
        <span class="hljs-keyword">int</span> numThreads = threadPool.getNumThreads();
        CountDownLatch latch = <span class="hljs-keyword">new</span> CountDownLatch(numThreads);

        <span class="hljs-comment">// Divide the array into segments based on the number of threads</span>
        <span class="hljs-keyword">int</span> segmentSize = (<span class="hljs-keyword">int</span>) Math.ceil((<span class="hljs-keyword">double</span>) length / numThreads);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; numThreads; i++) {
            <span class="hljs-keyword">int</span> start = i * segmentSize;
            <span class="hljs-keyword">int</span> end = Math.min(start + segmentSize, length);

            <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> segmentStart = start;
            <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> segmentEnd = end;
            threadPool.submitTask(() -&gt; {
                mergeSort(array, segmentStart, segmentEnd); <span class="hljs-comment">// Sorting the segment</span>
                latch.countDown();
            });
        }

        <span class="hljs-keyword">try</span> {
            latch.await(); <span class="hljs-comment">// Wait for all sorting tasks to complete</span>
        } <span class="hljs-keyword">catch</span> (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        <span class="hljs-comment">// Merge sorted segments until only one segment remains</span>
        <span class="hljs-keyword">int</span> interval = segmentSize;
        <span class="hljs-keyword">while</span> (interval &lt; length) {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; length; i += <span class="hljs-number">2</span> * interval) {
                <span class="hljs-keyword">int</span> start = i;
                <span class="hljs-keyword">int</span> mid = i + interval;
                <span class="hljs-keyword">int</span> end = Math.min(i + <span class="hljs-number">2</span> * interval, length);
                merge(array, start, mid, end);
            }
            interval *= <span class="hljs-number">2</span>;
        }
    }
</code></pre>
<p>This custom implementation of <code>ThreadPool</code> uses an <code>ExecutorService</code> that starts as many Threads as needed depending on the number of Tasks inside our <code>BlockingQueue</code>, up to <code>numThreads</code> Threads.</p>
<p><code>taskQueue.take()</code> calls until a task becomes available in the queue. Once a task is available, the thread will retrieve it from the queue and execute it. This ensures that worker threads are only active when there are tasks to be executed, preventing them from blocking indefinitely when the queue is empty.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.concurrent.BlockingQueue;
<span class="hljs-keyword">import</span> java.util.concurrent.ExecutorService;
<span class="hljs-keyword">import</span> java.util.concurrent.Executors;
<span class="hljs-keyword">import</span> java.util.concurrent.LinkedBlockingQueue;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThreadPool</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> numThreads;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ExecutorService executor;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BlockingQueue&lt;Runnable&gt; taskQueue;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">boolean</span> running;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ThreadPool</span><span class="hljs-params">(<span class="hljs-keyword">int</span> numThreads)</span></span>{
        <span class="hljs-keyword">this</span>.numThreads = numThreads;
        executor = Executors.newFixedThreadPool(<span class="hljs-keyword">this</span>.numThreads);
        taskQueue = <span class="hljs-keyword">new</span> LinkedBlockingQueue&lt;&gt;();
        running = <span class="hljs-keyword">true</span>;
        <span class="hljs-comment">// Start worker threads</span>
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; numThreads; i++){
            executor.execute(<span class="hljs-keyword">this</span>::workerLoop);
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">workerLoop</span><span class="hljs-params">()</span></span>{
        <span class="hljs-keyword">while</span> (running){
            <span class="hljs-keyword">try</span> {
                Runnable task = taskQueue.take();
                <span class="hljs-keyword">try</span>{
                    task.run();    
                } <span class="hljs-keyword">catch</span>(RuntimeException e){
                    handleException(e);
                }
            }
            <span class="hljs-keyword">catch</span> (InterruptedException e){
                Thread.currentThread().interrupt();
                <span class="hljs-keyword">break</span>;
            }
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleException</span><span class="hljs-params">(Exception e)</span></span>{
        e.printStackTrace();
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">submitTask</span><span class="hljs-params">(Runnable task)</span></span>{
        <span class="hljs-keyword">try</span> {
            taskQueue.put(task);
        } <span class="hljs-keyword">catch</span> (InterruptedException e){
            Thread.currentThread().interrupt();
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">shutdown</span><span class="hljs-params">()</span></span>{
        running = <span class="hljs-keyword">false</span>;
        executor.shutdown();
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNumThreads</span><span class="hljs-params">()</span></span>{
        <span class="hljs-keyword">return</span> numThreads;
    }
}
</code></pre>
<h3 id="heading-runtime-performance-analysis">Runtime Performance Analysis</h3>
<p>The tests I performed for data up to 1 billion numbers show that on multi-core systems the processing is faster, thus we were able to utilize multi-threading and concurrency to achieve better performance.</p>
<p>Merge Sort is red and it's concurrent version is blue. The numbers on the left are the execution time in ms, and on the bottom we have the number of elements that were sorted. For 2 threads, we achieved approx 2.1x faster execution time(7150ms vs 15017ms).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711411587862/5ac82fb5-4e72-449f-b1e9-0c6a865477d5.png" alt class="image--center mx-auto" /></p>
<p>When using 4 threads simultaneously, we achieved a 2.65x speedup(4906ms vs 13030ms).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711411898729/eb008f4e-b7cb-4d74-a6b4-d1656aa94b5c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Our exploration into Merge Sort, has showed us the significant impact of concurrency in improving performance and scalability. By comparing sequential and concurrent implementations, we've observed notable differences in runtime efficiency, particularly when handling large datasets.</p>
<p>Sequential implementations, while straightforward, can become bottle-necked when confronted with sizable datasets due to their inability to fully leverage the available computational resources. On the other hand, concurrent implementations use the power of parallelism, distributing the workload across multiple threads and substantially reducing processing time.</p>
<p>Although there are built-in functionalities in Java for concurrent sorting that may be faster such as <code>ForkJoinPool</code> and <code>Arrays.parallelSort()</code> , this article went to show how parallelism works in detail and it’s implementation for MergeSort.</p>
<p>In the field of software development, understanding the nuances of concurrency becomes increasingly crucial when dealing with performance-critical applications.</p>
<p>By using concurrency, we allow ourselves to build robust, scalable, and high-performance. However, it's essential to recognize that concurrency introduces its own set of challenges. Careful design and optimization are necessary to reap the benefits of concurrency effectively.</p>
]]></content:encoded></item></channel></rss>