Skip to content

Navigating Parallelism in Functional Programming. Setting the Right Course

Posted on:September 1, 2023 at 03:13 PM

Welcome back, intrepid coders! In this intriguing chapter of our journey through functional programming, we are about to embark on an adventure into the mystical realm of parallelism. Just like a curator selecting the perfect frame for a masterpiece, we’ll explore how to set the parallelism level for your code using the art of thread pools.

Table of contents

Open Table of contents

Sections

The Fork-Join Pool: Threads in Harmony

Imagine our journey into parallelism as an art gallery, where each piece of art represents a thread in the world of coding. To appreciate these threads, we must visit the central exhibit – the Fork-Join Pool. This special pool of threads is the beating heart of parallel stream operations in Java.

By default, the Fork-Join Pool is a dynamic entity that allocates threads based on the available processing power of your system. It’s like having a gallery that magically adapts its space to accommodate more art pieces when a crowd gathers. To determine the number of available processors in your system, you can use the availableProcessors method on the Runtime object.

int processors = Runtime.getRuntime().availableProcessors();

In our art gallery analogy, if your system has four art enthusiasts (processors), the Fork-Join Pool will allocate four threads. But, wait, why did it print three threads when you tried it with your four-core machine? Well, one thread is always reserved for the main program. So, you get four minus one, which equals three threads in the pool.

Taming the Fork-Join Pool: Setting Parallelism

Now, let’s wield our curator’s brush to set the parallelism level for the Fork-Join Pool. With great power comes great responsibility, and controlling parallelism is no exception. We can use a simple property to fine-tune the number of threads:

int processors = Runtime.getRuntime().availableProcessors();

Here, we’ve set the parallelism level to 2, which means the Fork-Join Pool will use two cores. If you were to omit this line, it would utilize all available cores. However, tread carefully; setting parallelism requires strategic thinking.

But what if you want to take control of your art gallery and create a custom space for your threads? Just like opening a private exhibition, you can create your Fork-Join Pool with a specified number of threads.

ForkJoinPool pool = new ForkJoinPool(2);

In this scenario, we’ve opted for two threads, just like showcasing two masterpieces in your private art collection.

Applying Parallelism to Real-World Tasks

Now that we’ve mastered the art of setting parallelism let’s dive into a practical example. Picture your code as company featuring a list of employees.

List<Employee> employees = new ArrayList<>();
// ... Populate the list with 600 employees ...

Your task is to count the number of employees with a salary greater than $1000.

Callable<Long> task = () -> employees.parallelStream()
    .filter(employee -> employee.getSalary() > 1000)
    .count();

In this masterpiece of code, we’ve created a Callable task that encapsulates our operation. This task counts the employees meeting our criteria in parallel.

Finally, we retrieve the value from the task using get():

long count = task.get();

Voila! We have the count of employees with salaries over $1000.

The Thread Tapestry: A Word of Caution

As we wrap up our artistic exploration of parallelism, remember that while threads can enhance performance, they come with responsibilities. Using parallelism judiciously is crucial to avoid any performance pitfalls.

Here’s a quick guideline:

1 - Computational Intensive (CPU Bound): If your task involves heavy calculations or logic, the number of threads should be less than or equal to the number of CPU cores.

2 - IO Intensive (IO Bound): If your task involves a lot of waiting, such as file operations, database queries, or HTTP calls, the number of threads can exceed the number of cores, as the application often spends time waiting for IO operations to complete.

Choosing the right number of threads is an art in itself. Too few, and you won’t fully utilize your hardware; too many, and they may trip over each other, causing performance issues. So, as you navigate the parallelism waters, remember: set your parallelism wisely, craft your Fork-Join Pools with care, and apply parallelism thoughtfully. Parallelism is a tool, and like any tool, it’s most effective in the hands of a skilled craftsman.

Until our next artistic coding adventure, may your threads be synchronized, your code be efficient, and your applications be a true masterpiece!

You can find the repo for this section of the course Here