Runnable, Callable, Future, Executor en Java y Android Programación multiproceso

Multithreading es una característica de Java que permite la ejecución simultánea de dos o más partes de un programa para la máxima utilización de la CPU. Cada parte de un programa de este tipo se denomina hilo. Entonces, los hilos son procesos livianos dentro de un proceso.

Ejecutable

Cualquier clase cuyas instancias estén destinadas a ser ejecutadas por un subproceso debe implementar la interfaz Runnable. La clase debe definir un método de ejecución sin argumentos. Esta interfaz está destinada a proporcionar un protocolo estándar para los objetos que desean ejecutar código mientras están activos. Thread, por ejemplo, implementa la interfaz Runnable. Estar activo simplemente significa que un hilo ha comenzado y aún no ha terminado. Además, Runnable permite que una clase esté activa sin subclasificar Thread. Una clase que implementa Runnable puede ejecutar código sin crear una subclase de Thread creando una instancia de Thread y pasándose a sí misma como el destino.

Para crear un nuevo hilo con Runnable, siga estos pasos:

  1. Cree un implementador Runnable y llame al método run().
  2. Cree una instancia de Thread y pásele el implementador. Thread tiene una función Object() { [código nativo] } que acepta instancias Runnable.
  3. Llame a start() en la instancia de Thread; start llama a run() del implementador internamente. Invocar start() genera un nuevo Thread que ejecuta el código especificado en run().

Java

public class Comment implements Activity {
    private Date GeeksCreatedAt;
    public Comment(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
    @Override public String toString()
    {
        return "Comment{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}
public class GfG implements Activity {
  
    private Date GeeksCreatedAt;
  
    public GfG(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCoursesAddedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "GfG{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}

Llamable

Una tarea que produce un resultado y tiene la capacidad de lanzar una excepción. Los implementadores definen un único método llamado llamada que no acepta argumentos. La interfaz Callable es similar a la interfaz Runnable en que ambas están destinadas a clases cuyas instancias pueden ser ejecutadas por otro subproceso. Un Runnable, por otro lado, no devuelve un valor y no puede generar una excepción comprobada. Los ejecutores contienen métodos de utilidad para convertir otras formas comunes a clases invocables. Para implementar un Runnable, se debe implementar el método run(), que no devuelve nada, mientras que, para implementar un Callable, se debe implementar el método call(), que devuelve un resultado al finalizar. Es importante tener en cuenta que no se puede crear un hilo con un Callable; solo un Runnable puede hacerlo.

Java

public class Like implements Activity {
    private Date GeeksCreatedAt;
  
    public Like(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Like{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}

Java

public class Post implements Activity {
    private Date GeeksCreatedAt;
    public Post(Date GeeksCreatedAt)
    {
        this.GeeksCreatedAt = GeeksCreatedAt;
    }
  
    @Override public Date getCreatedAt()
    {
        return GeeksCreatedAt;
    }
  
    @Override public String toString()
    {
        return "Post{"
            + "GeeksCreatedAt=" + GeeksCreatedAt + '}';
    }
}

Futuro

Un futuro es el resultado de un cálculo asíncrono. Se proporcionan métodos para determinar si el cálculo está completo, para esperar a que finalice y para recuperar el resultado del cálculo. Cuando finaliza el cálculo, el resultado solo se puede recuperar usando el método get, bloqueando si es necesario hasta que esté listo. El método de cancelación se utiliza para cancelar una transacción. Se proporcionan métodos adicionales para determinar si la tarea se completó normalmente o no. Una vez que se ha completado un cálculo, no se puede cancelar. Si desea utilizar un futuro para la cancelación pero no proporciona un resultado utilizable, puede declarar Future? tipos y devuelve nulo como resultado de la tarea subyacente. Debido a que implementa la interfaz Future, todas las interacciones con el subproceso después de que comienza son manejadas por el objeto FutureTask. Como resultado, no hay necesidad de guardar los objetos Thread. El objeto FutureTask se puede usar para cancelar la tarea, verificar si está completa o intentar recuperar el resultado.

Java

public class RemoteService {
    private static int cores
        = Runtime.getRuntime().availableProcessors();
    private static ExecutorService executor
        = Executors.newFixedThreadPool(cores + 1);
    public void stop() { executor.shutdown(); }
    public void
    getUserRecentGfgActs(ResultCallback callback)
    {
        executor.execute(() -> {
            List<Like> gfgLikes = new ArrayList<>();
            List<Post> gfgPOsts = new ArrayList<>();
            List<Comment> comments = new ArrayList<>();
            List<Friend> gfgCourses = new ArrayList<>();
            Future<List<Like> > futureGfgLikes
                = executor.submit(getGfgLikes(
                    "https://geeksforgeeks.org.com/gfgLikes"));
            Future<List<Comment> > futureComments
                = executor.submit(getComments(
                    "https://geeksforgeeks.org.com/comments"));
            Future<List<Post> > futureGfgPOsts
                = executor.submit(getGfgPOsts(
                    "https://geeksforgeeks.org.com/gfgPOsts"));
            Future<List<Friend> > futureGfgCourses
                = executor.submit(getGfgCourses(
                    "https://geeksforgeeks.org.com/gfgCourses"));
  
            try {
                gfgLikes = futureGfgLikes.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgPOsts = futureGfgPOsts.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                comments = futureComments.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            try {
                gfgCourses = futureGfgCourses.get();
            }
            catch (InterruptedException
                   | ExecutionException e) {
                e.printStackTrace();
            }
  
            List<Activity> gfgActs = new ArrayList<>();
            gfgActs.addAll(gfgLikes);
            gfgActs.addAll(gfgPOsts);
            gfgActs.addAll(comments);
            gfgActs.addAll(gfgCourses);
  
            Collections.sort(
                gfgActs,
                (activity1, activity2)
                    -> activity1.getCreatedAt().compareTo(
                        activity2.getCreatedAt()));
  
            callback.onResult(gfgActs);
        });
    }
  
    private Callable<List<Like> > getGfgLikes(String url)
    {
        return () ->
        {
            System.out.println("getGfgLikes");
            Thread.sleep(200);
            return Arrays.asList(
                new Like(new Date(1534334348560L)),
                new Like(new Date(1554365436546960L)));
        };
    }
  
    private Callable<List<Post> > getGfgPOsts(String url)
    {
        return () ->
        {
            System.out.println("getGfgPOsts");
            Thread.sleep(500);
            return Arrays.asList(
                new Post(new Date(15334343448560L)),
                new Post(new Date(153343434460L)));
        };
    }
  
    private Callable<List<Comment> > getComments(String url)
    {
        return () ->
        {
            System.out.println("getComments");
            Thread.sleep(200);
            return Arrays.asList(
                new Comment(new Date(15356565648560L)),
                new Comment(new Date(151454545456460L)));
        };
    }
  
    private Callable<List<Friend> >
    getGfgCourses(String url)
    {
        return () ->
        {
            System.out.println("getGfgCourses");
            Thread.sleep(6500);
            return Arrays.asList(
                new Friend(new Date(1534543354248560L)),
                new Friend(new Date(15334343546460L)));
        };
    }
}

Ejecutor

Un objeto que ejecuta tareas ejecutables que se han enviado. Esta interfaz le permite desvincular el envío de tareas de la mecánica de cómo se ejecutará cada tarea, como el uso de subprocesos, la programación, etc. En lugar de crear subprocesos explícitamente, normalmente se usa un Ejecutor. En lugar de invocar a new Thread(new(RunnableTask())), por ejemplo. start() para cada tarea en una secuencia. Es, como su nombre lo indica, un grupo de subprocesos con un número fijo de subprocesos. Las tareas enviadas al ejecutor son ejecutadas por n subprocesos y cualquier tarea adicional se almacena en LinkedBlockingQueue. Emplea una cola de bloqueo.

Creación y ejecución de un ejecutor simple, en el que crearemos una tarea y la ejecutaremos en un grupo fijo.

  1. La clase Task implementa Callable y tiene un parámetro String. También se indica que arrojará una excepción.
  2. Para ejecutar una tarea en la clase «Tarea», primero debemos instanciar la clase Tarea y pasarla al ejecutor para su ejecución.
  3. El resultado del objeto Futuro debe imprimirse y mostrarse.

Publicación traducida automáticamente

Artículo escrito por therebootedcoder 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 *