Global control for ExecutorService

0

Rodo software locally in Java SE, basically it is the synoptic of a field equipment, and can be controlled by this software. The user has several functions within it, being able to call, change status, settings, etc.

Each function is performed by a separate thread, so as not to compromise the UI. I would like to centralize the creation of these command threads by creating a global class that would return the ExecutorService

Is it worth turning this into a "global" scope within my application, or working with the Executors separated by command would be the most correct?

Example of a global class of ExecutorService (basic):

    class GlobalThreadPool {

      int maximumPoolSize = 4;

      final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Orders-%d").setDaemon(true).build();

      final ExecutorService executorService = Executors.newFixedThreadPool(maximumPoolSize, threadFactory);

    }
    
asked by anonymous 15.05.2017 / 13:40

1 answer

2

If the program has several different interactions with threads, it makes sense to centralize and encapsulate this functionality in a specialized class.

On the name, I would avoid anything with a "global" name and, in this case, setting out implementation details.

A priori, I would model this class first by defining interfaces for the manager that performs the functions of the program and for the commands. Example:

interface Comando {
    void executar();
}

interface GerenciadorExecucao {
    void executar(Comando c);
}

Note that interfaces do not tell you how commands will run. This detail will be managed by the implementation and the other classes have nothing to do with it, for them this is transparent, they just wait for the command to execute.

Regarding the implementation, I would create a class called GerenciadorExecucaoAssincrono containing a thread pool whose threads consume the commands of a synchronized queue like LinkedBlockingQueue . Example;

class GerenciadorExecucaoAssincrono implements GerenciadorExecucao {
    private final int maximumPoolSize = 4;
    private final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Orders-%d").setDaemon(true).build();
    private final ExecutorService executorService = Executors.newFixedThreadPool(maximumPoolSize, threadFactory);
    private final LinkedBlockingQueue<Comando> queue = new LinkedBlockingQueue<>()

    public GerenciadorExecucaoAssincrono() {
        //thread que fica em loop infinito consumindo os comandos da fila
        executorService.submit(() -> {
            while(true) {
                Comando c = queue.take(); //espera por um comando na fila
                c.executar();
            }
        });
    }

    public void executar(Comando c) {
        //adiciona o comando à fila, desbloqueando a thread acima
        queue.put(c);
    }
}

Now you can create any command implementation in other classes. In this way, each functionality of your system can use the new asynchronous execution API and decoupled.

In the example above, I created a single thread consuming the commands, so the result is that the commands are executed in the same order as they are added to the queue.

However, you can have multiple threads and run them in parallel, just submit several times the same Runnable that I put in the lambda above. The problem with this is that commands executed at the same time could have an unwanted effect, since you have physical equipment and possible limitations. It's up to you to analyze this and think about the best strategy.

    
20.05.2017 / 11:35