La aplicación principal implementa Runnable | Enfoque de programación concurrente 2

Requisito previo: diferentes enfoques para la programación concurrente en Java

Veamos el segundo enfoque en detalle.

  1. El usuario tiene la clase principal que implementa ejecutable , que es una promesa para el compilador de que la clase tendrá un método de ejecución .
    public class MyClass implements Runnable{
        public void run(){
    
        }
    }
    
  2. Luego, el usuario pasa una referencia a la aplicación principal al método de ejecución utilizando esta palabra clave.
    taskList.execute(this)
    

    Esta es la forma de transmitirle al compilador que cuando se ejecuta una tarea en particular, llámelo como el método de ejecución respectivo.

  3. La ventaja de este enfoque sobre el enfoque uno es que el método de ejecución puede llamar a métodos en la aplicación principal, incluidos los privados.
  4. La desventaja de este enfoque sobre el primer enfoque son las condiciones de carrera. La razón por la que colocamos el método de ejecución en la aplicación principal es para que pueda manejar datos en la aplicación principal. Si el usuario inicia más de un hilo y están modificando simultáneamente los mismos datos compartidos, entonces hay condiciones de carrera de las que preocuparse. En segundo lugar, no hay un constructor , lo que hace que sea muy difícil pasar los argumentos del constructor, por lo que cada clase comienza de la misma manera.
  5. Código de muestra: el usuario implementa ejecutable en la clase principal y la misma clase también tiene muchos otros métodos para hacer la cola de tareas y llamar al método de ejecución.

La siguiente es la implementación del enfoque 2 del contraejemplo explicado en el enfoque uno:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
  
// Concurrent Programming in action
public class MainAppRunnable implements Runnable {
  
    private final int loopLimit;
  
    // Limit till which the counter will run
    private MainAppRunnable(int loopLimit)
    {
        this.loopLimit = loopLimit;
    }
  
    private void startThreads()
    {
  
        // Made the task queue
        ExecutorService taskList
            = Executors.newFixedThreadPool(2);
  
        // Added these to the task queue
        // and made available for execution
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
  
        // Stopped new tasks from being
        // added to the task queue
        taskList.shutdown();
    }
  
    @Override
    public void run()
    {
        for (int i = 0; i < loopLimit; i++) {
            System.out.println(
                Thread.currentThread().getName()
                + " Counter: " + i);
        }
  
        // Called private method that is
        // part of the same application
        pause(Math.random());
    }
  
    // Methods that run uses can be private
    // in this approach
    private void pause(double seconds)
    {
        try {
            Thread
                .sleep(Math.round(seconds * 1000.0));
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  
    // Driver method
    public static void main(String[] args)
    {
        new MainAppRunnable(3).startThreads();
    }
}

Producción:

pool-1-thread-1 Counter: 0
pool-1-thread-2 Counter: 0
pool-1-thread-1 Counter: 1
pool-1-thread-1 Counter: 2
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-2 Counter: 0
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-2 Counter: 0
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-1 Counter: 0
pool-1-thread-1 Counter: 1
pool-1-thread-1 Counter: 2

Publicación traducida automáticamente

Artículo escrito por AnureetKaur y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *