ConcurrentHashMap Parallel Operations

Introduction

In Java 8, the forEach, search and reduce methods of the ConcurrentHashMap have parallel operation capability. Normally, it is indicated by the parameter called parallelismThreshold. This parameter specifies the number of elements before the execution becomes parallel. For example, if the parallelismThreshold is 10 then if the number of elements to process is below 10 then it will be processed in the current thread (i.e. single thread) otherwise it will be processed in parallel.

Using the forEach method

The forEach method has different overloads but we will just be focusing on the simplest one. The one that accepts parallelismThreshold and BiConsumer parameters. To demonstrate parallel execution in action lets start with the ConcurrentHashMap that has items less than the parallelismThreshold like the following snippet (see the complete code at the bottom):

Snippet 1 - Elements less than parallelismThreshold
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

//This will generate a stream with 1 to 9 as integer content.
IntStream.range(1, 10).forEach(item -> map.put(String.valueOf(item), item));

long parallelismThreshold = 10;

BiConsumer<String, Integer> biConsumer = (key, value) -> {
    System.out.println("key: " + key + " value: " + value + " thread: " + Thread.currentThread().getName());
};

map.forEach(parallelismThreshold, biConsumer);

Running the above snippet will not run in parallel execution since the items in the map is less than the parallelismThreshold. But updating the variable parallelismThreshold variable to 9 and run it again. We must see an output like the following output:

Output 1 - Updating the parallelismThreshold to 9 in snippet 1
key: 1 value: 1 thread: main
key: 8 value: 8 thread: ForkJoinPool.commonPool-worker-1
key: 2 value: 2 thread: main
key: 9 value: 9 thread: ForkJoinPool.commonPool-worker-1
key: 3 value: 3 thread: main
key: 4 value: 4 thread: main
key: 5 value: 5 thread: main
key: 6 value: 6 thread: main
key: 7 value: 7 thread: main

Notice the ForkJoinPool.commonPool-worker thread which indicates that the forEach method is operating on parallel.

Using the search method

The search method is the functionality to find an item in the map with parallel support. This methods has siblings namely: searchEntries, searchKeys and searchValues but we will just be focusing on the search method with parallelismThreshold and BiFunction parameters. For the sample usage, see the following snippet (see the complete code at the bottom).

Snippet 2 - Sample usage of search method
BiFunction<String, Integer, Integer> biFunction = (key, value) -> {

    if (key.equals("9")) {
        return value; //Stop searching.
    }
    return null; //Continue searching.
};

System.out.println("Value: " + map.search(parallelismThreshold, biFunction));

We can run the previous snippet after concatenating it with snippet 1. The search will stop when the BiFunction implementation return non-null value. Otherwise, the search will continue. This is good if you have a big map.

Using the reduce method

The reduce method is the one to use if we need to accumulate something from the map items to produce a single result. This also supports parallel operation and has many siblings (e.g. reduceEntries, reduceKeys, reduceValues, etc ...). But, we will only focus on the reduce method itself that accepts parallelismThreshold, transformer (i.e. BiFunction) and reducer (i.e. BiFunction).

The transformer parameter is the one that prepares what the reducer will work on. Like for example if the wanted to work on the values of the map from snippet 1. The transformer would be something like the following:

Snippet 3 - Transformer logic
BiFunction<String, Integer, Integer> transformer = (key, value) -> value;

Knowing what the transformer will give us. We can write a reducer logic what will add all the values returned by the transformer logic like the following:

Snippet 4 - Reducer logic
BiFunction<Integer, Integer, Integer> reducer = (aggr, value) -> aggr + value;

From the snippet above, the aggr parameter is a variable the accumulates the value argument.

Having the transformer and the reducer ready we can invoke the reduce method like the following (see the complete code at the bottom):

Snippet 5 - Invoking the reduce method
System.out.println("Total: " + map.reduce(parallelismThreshold, transformer, reducer));

The Complete Code

package xyz.ronella.concurrency;

import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.IntStream;

public class HashMap {
    public static void main(String ... args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

        //This will generate a stream with 1 to 9 as integer content.
        IntStream.range(1, 10).forEach(item -> map.put(String.valueOf(item), item));

        long parallelismThreshold = 9;

        BiConsumer<String, Integer> biConsumer = (key, value) -> {
            System.out.println("key: " + key + " value: " + value + " thread: " + Thread.currentThread().getName());
        };

        map.forEach(parallelismThreshold, biConsumer);

        BiFunction<String, Integer, Integer> biFunction = (key, value) -> {
            if (key.equals("9")) {
                return value; //Stop searching.
            }
            return null; //Continue searching.
        };

        System.out.println("Value: " + map.search(parallelismThreshold, biFunction));

        BiFunction<String, Integer, Integer> transformer = (key, value) -> value;

        BiFunction<Integer, Integer, Integer> reducer = (aggr, value) -> aggr + value;

        System.out.println("Total: " + map.reduce(parallelismThreshold, transformer, reducer));
    }
}

Range in Java

To create a range in java we can use the following from the java.util.stream package:

  • IntStream.range(int startInclusive, int endExclusive)
  • IntStream.rangeClosed(int startInclusive, int endInclusive)
  • LongStream.range(int startInclusive, int endExclusive)
  • LongStream.rangeClosed(int startInclusive, int endInclusive)

IntStream.range Method Example

IntStream.range(1, 10).forEach(item -> System.out.println(item));

Output

1
2
3
4
5
6
7
8
9

IntStream.rangeClosed Method Example

IntStream.rangeClosed(1, 10).forEach(item -> System.out.println(item));

Output

1
2
3
4
5
6
7
8
9
10

Using CyclicBarrier with Java

CyclicBarrier was designed to allow threads to wait for each other to a certain barrier and doing it again and again (i.e. the reason why it is called cyclic).

Creating a CyclicBarrier aware Task
  1. Create a task that will accepts and instance of CyclicBarrier like the following snippet (i.e. the complete code will be at the bottom).
    public Teller(CyclicBarrier barrier, String message) {
        _barrier = barrier;
        _message = message;
    }
  2. Within the task we must call the await method of the instance of the CyclicBarrier like the following snippet (i.e. the complete code will be at the bottom). The number of call to this method is the one being tracked by the instance of the CyclicBarrier to compare to the number of parties (i.e. normally the first or only argument of the constructor.) specified during it's initialization.
    @Override
    public String call() throws Exception {
        System.out.println("Processing: " + _message);
        _barrier.await();
        return _message;
    }
Using the CyclicBarrier aware Task
  1. Create an instance of CyclicBarrier class with the expected number of parties (i.e. normally this is the first or only argument of the constructor) before it unblocks itself for all the threads waiting then back to blocking. Optionally, we can also pass a second argument of type Runnable that will only be invoked when the barrier unblocks like the following snippet (i.e. the complete code will be at the bottom).
    CyclicBarrier barrier = new CyclicBarrier(2 /*The number of parties. */
    , () -> System.out.println("Barrier open.") /*The logic to call when the barrier unblocks. */
    );
  2. Submit a number of tasks that corresponds to the multiple of the number of parties (e.g. from step 1 it could be multiple of 2) from step 1 like the following snippet (i.e. the complete code will be at the bottom):
    futures.add(executor.submit(new Teller(barrier, "One")));
    futures.add(executor.submit(new Teller(barrier, "Two")));
    futures.add(executor.submit(new Teller(barrier, "Three")));
    futures.add(executor.submit(new Teller(barrier, "Four")));
    
    futures.forEach((Future future) -> {
        try {
            System.out.println(future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    });
Observation

Upon running the complete code:

  • We must notice that the following message will be executed every multiple of 2 (i.e. observe the processing message):
    Barrier open.
  • The following message (i.e. can be in any order) will never be displayed before One and Two (i.e. can be in any order):
    Three
    Four
The Complete Code
package xyz.ronella.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Barrier {

    public static void main(String[] args) {

        class Teller implements Callable {

            private CyclicBarrier _barrier;
            private String _message;

            public Teller(CyclicBarrier barrier, String message) {
                _barrier = barrier;
                _message = message;
            }

            @Override
            public String call() throws Exception {
                System.out.println("Processing: " + _message);
                _barrier.await();
                return _message;
            }
        }

        ExecutorService executor = Executors.newFixedThreadPool(2);

        CyclicBarrier barrier = new CyclicBarrier(2 /*The number of parties. */
                , () -> System.out.println("Barrier open.") /*The logic to call when the barrier unblocks. */
        );

        List<Future> futures = new ArrayList<>();

        try {
            futures.add(executor.submit(new Teller(barrier, "One")));
            futures.add(executor.submit(new Teller(barrier, "Two")));
            futures.add(executor.submit(new Teller(barrier, "Three")));
            futures.add(executor.submit(new Teller(barrier, "Four")));

            futures.forEach((Future future) -> {
                try {
                    System.out.println(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            });
        }
        finally {
            executor.shutdown();
        }
    }
}

Behavioral Design Patterns

Behavioral design patterns are design patterns that are focusing on the interactions between objects and mostly trying to be loosely coupled.

  • Chain of Responsibility
    If the intent is to decouple a request from a handler in a chain of handlers until it is finally recognized, use this pattern.
  • Command
    If the intent is to encapsulate a request as an object, use this pattern.
  • Interpreter
    If the intent is to interpret a grammar of a language, use this pattern.
  • Iterator
    If the intent is to navigate a container without exposing the structure of an object, use this pattern.
  • Mediator
    If the intent is to make objects interacts without them really referring to each other, this is the pattern to use.
  • Memento
    If the intent is to externalize the object state that normally provides rollback functionality, use this pattern.
  • Null Object
    If the intent is to avoid an explicit null check, use this pattern to encapsulate the default behavior or do nothing behavior.
  • Observer
    If the intent is to have a subject that can be observed by one or more observers, use this pattern.
  • State
    If the intent is to have the state as part of an object rather than storing it in a variable, use this pattern.
  • Strategy
    If the intent is to select an algorithm at runtime, use this pattern.
  • Template method
    If the intent is to define an algorithm that allows the sub-classes to redefine parts without changing it's structure, use this pattern.
  • Visitor
    If the intent is to separate the algorithm from an object structure, this is the pattern to use.

Structural Design Patterns

Structural Design Patterns

Structural design patterns are design patterns that are mainly focusing on how to use objects (e.g. Performance, memory utilization, interception).

  • Adapter
    If an interface of another class needs to be used as another interface, use this pattern.
  • Bridge
    If the abstraction need to be decoupled from the implementation and allowing both to be modified without affecting each other, use this pattern.
  • Composite
    If the intent is to have some objects of the same type into tree structure, use this pattern.
  • Decorator
    If adding a behavior to an object of the same type dynamically at runtime without affecting their own behavior, use this pattern.
  • Facade
    If the need of have a simplified interface from a complex and difficult to use API because of the large interdependent classes or the codes is not accessible, use this pattern.
  • Filter (a.k.a. Criteria)
    If the intent is to filter a set of objects using different criteria and has the capability to chain them in a decoupled way, use this pattern.
  • Flyweight
    If the desire to conserve memory by sharing as much data as possible, use this pattern.
  • Proxy
    If there's a need for a class to function as an interface to something else, use this pattern. The proxy can just forward to the a real object or provides some additional logic.

Creational Design Patterns

Creational design patterns are design patterns that mainly focusing on the creation of object that's appropriate to a particular scenario.

  • Singleton
    Only one an only instance of a particular class is required, use this pattern.
  • Builder
    If the creation of objects are complex (i.e. requires a lot of constructors and properties), this is the pattern of choice.
  • Prototype
    When the object creation is so expensive and cloning is more lighter, this is the pattern of choice.
  • Factory
    If hiding the instantiation logic was desired and only exposes the common interface, use this pattern.
  • Abstract Factory
    If multiple factories were created and have a common objectives we can group these to an abstract factory. This is also known as factory of factories.
  • Dependency Injection
    If the intent is to have an object supplies the dependencies of another object, this is the pattern to use.

Hashing a Password in Java

  1. Create an instance of SecretKeyFactory using the desired algorithm (see. https://docs.oracle.com/javase/8/docs/api/index.html?javax/crypto/SecretKeyFactory.html) like the following:
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");

    Note: The PBKDF2WithHmacSHA512 is the algorithm to construct the secret key using the Password-Based Key Derivation Function.

  2. Synthesize the raw materials into the instance of PBEKeySpec using the following syntax:
    PBEKeySpec spec = new PBEKeySpec( <PASSWORD>, <SALT>, <ITERATIONS>, <KEY_LENGTH> );
    Parameter Description
    <PASSWORD> The raw password (i.e. in array of chars)
    <SALT> A text (i.e. in array of bytes) that will be included to password.
    <ITERATIONS> The desired number of iterations that the <PASSWORD> along with the <SALT> will be encoded. The higher the number the better to deter some kind of attack (e.g. rainbow).
    <KEY_LENGTH> The length (i.e. in bits) of the key. Normally you can find this value on the algorithm name (e.g. PBKDF2WithHmacSHA512).
  3. Create a SecretKey instance using the spec from step 2 using the following:
    SecretKey key = skf.generateSecret(spec);
  4. Retrieve the encoded hash using the getEncoded() method of the SecketKey instance like the following:
    byte[] encodedKey = key.getEncoded();
  5. Use Base64 encoder to  covert the encoded key to string like the following:
    String base64Str = Base64.getEncoder().encodeToString(encodedKey);

Example code

package xyz.ronella.crypto;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

public class PasswordHashing {
    public static void main(String[] args) {
        try {
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");

            PBEKeySpec spec = new PBEKeySpec("PASSWORD".toCharArray(), "SALT".getBytes(), 10000, 512);
            SecretKey key = skf.generateSecret(spec);

            byte[] encodedKey = key.getEncoded();
            String base64Str = Base64.getEncoder().encodeToString(encodedKey);

            System.out.println(base64Str);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }
}

Always On Top using AutoHotKey

  1. Create an autohotkey script (e.g. alwaysontop.ahk).
  2. Add the following entries:
    #^+t::
    	WinSet, AlwaysOnTop, On, A
    Return
    
    #^t::
    	WinSet, AlwaysOnTop, Off, A
    Return

    Example script

    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    ; #Warn  ; Enable warnings to assist with detecting common errors.
    SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    
    #^+t::
    	WinSet, AlwaysOnTop, On, A
    Return
    
    #^t::
    	WinSet, AlwaysOnTop, Off, A
    Return

To make a window always on top press the following combination:

Win + Ctrl + Shift + t

To disable the effect of the always on top press the following combination:

Win + Ctrl + t

Changing Jenkins Port

  1. Open the file jenkins.xml from the location where Jenkins was installed (e.g. C:\Program Files (x86)\Jenkins).
  2. Search for httpPort and updated it with whatever you wanted it to be (e.g. 9080) as long as it doesn't introduce any conflicts.

    Example update to 9080

    <arguments>-Xrs -Xmx256m -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort=9080 --webroot="%BASE%\war"</arguments>