Maison  >  Article  >  Java  >  Introduction détaillée à Callable et Future dans le multithreading Java (exemple de code)

Introduction détaillée à Callable et Future dans le multithreading Java (exemple de code)

不言
不言avant
2019-02-11 11:01:412801parcourir

Le contenu de cet article est une introduction détaillée (exemple de code) sur Callable et Future dans le multi-threading Java. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

La raison pour laquelle Callable et Future apparaissent

Il existe deux façons de créer un thread, l'une consiste à hériter directement de Thread et l'autre à implémenter l'interface Runnable .
Les deux méthodes ont un défaut : les résultats d'exécution ne peuvent pas être obtenus une fois la tâche exécutée.
Si vous avez besoin d'obtenir les résultats d'exécution, vous devez obtenir l'effet via des variables partagées ou une communication par thread, ce qui est plus difficile à utiliser.
Depuis Java 1.5, Callable et Future ont été fournis, grâce auxquels les résultats de l'exécution de la tâche peuvent être obtenus une fois l'exécution de la tâche terminée.

Introduction à Callable et Future

L'interface Callable représente un morceau de code qui peut être appelé et renvoie des résultats ; l'interface Future représente une tâche asynchrone, qui est la futur donné par la tâche qui n’est pas encore terminée. Ainsi, Callable est utilisé pour générer des résultats et Future est utilisé pour obtenir des résultats.
L'interface Callable utilise des génériques pour définir son type de retour. La classe Executors fournit des méthodes utiles pour exécuter des tâches dans le Callable dans le pool de threads. Puisque la tâche Callable est parallèle (parallèle signifie que tout semble parallèle, en fait, un seul thread s'exécute à un certain moment), nous devons attendre le résultat qu'elle renvoie.
L'objet java.util.concurrent.Future résout ce problème pour nous. Une fois que le pool de threads a soumis la tâche Callable, un objet Future est renvoyé. Vous pouvez l'utiliser pour connaître l'état de la tâche Callable et obtenir le résultat de l'exécution renvoyé par le Callable. Future fournit la méthode get() afin que nous puissions attendre la fin du Callable et obtenir ses résultats d'exécution.

Callable et Runnable

java.lang.Runnable, c'est une interface, et une seule méthode run() y est déclarée :

public interface Runnable {
    public abstract void run();
}

Étant donné que la valeur de retour de la méthode run() est de type void, aucun résultat ne peut être renvoyé une fois la tâche exécutée.

Callable se trouve sous le package java.util.concurrent C'est aussi une interface et n'y déclare qu'une seule méthode, mais cette méthode est appelée call() :

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Ceci. Il s'agit d'une interface générique et le type renvoyé par la fonction call() est le type V transmis.

Utilisation de Callable

Généralement, il est utilisé conjointement avec ExecutorService Plusieurs versions surchargées de la méthode submit sont déclarées dans l'interface ExecutorService.

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

Le type de paramètre dans la première méthode de soumission est Callable.

Pour le moment, il vous suffit de savoir que Callable est généralement utilisé en conjonction avec ExecutorService. La méthode d'utilisation spécifique sera décrite plus loin.

Généralement, nous utilisons la première méthode de soumission et la troisième méthode de soumission, et la deuxième méthode de soumission est rarement utilisée.

Future

Future consiste à annuler le résultat de l'exécution d'une tâche Runnable ou Callable spécifique, à demander si elle est terminée et à obtenir le résultat. Si nécessaire, vous pouvez obtenir le résultat de l'exécution via la méthode get, qui se bloquera jusqu'à ce que la tâche renvoie le résultat.

La classe Future se trouve sous le package java.util.concurrent. C'est une interface :

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Il y a 5 méthodes déclarées dans l'interface Future. expliqué ci-dessous
  • La méthode d'annulation est utilisée pour annuler la tâche. Si l'annulation de la tâche réussit, elle renvoie true. Si l'annulation de la tâche échoue, elle renvoie false. Le paramètre mayInterruptIfRunning indique s'il est autorisé à annuler les tâches en cours d'exécution mais qui ne sont pas terminées. S'il est défini sur true, cela signifie que les tâches en cours d'exécution peuvent être annulées. Si la tâche est terminée, que mayInterruptIfRunning soit vrai ou faux, cette méthode renverra certainement false, c'est-à-dire que si la tâche terminée est annulée, elle renverra false si la tâche est en cours d'exécution, si mayInterruptIfRunning est défini sur true ; il retournera true, si mayInterruptIfRunning est défini sur false , puis retournera false ; si la tâche n'a pas été exécutée, alors que mayInterruptIfRunning soit true ou false, elle retournera certainement true.

  • La méthode isCancelled indique si la tâche est annulée avec succès. Si la tâche est annulée avec succès avant qu'elle ne soit terminée normalement, elle renvoie vrai. La méthode

  • isDone indique si la tâche est terminée. Si la tâche est terminée, elle renvoie vrai

  • la méthode get() est utilisée ; pour obtenir le résultat de l'exécution. Cette méthode bloquera et attendra que la tâche soit terminée avant de revenir

  • get(long timeout, TimeUnit unit) est utilisé pour obtenir le résultat de l'exécution. il n'a pas été obtenu dans le délai imparti. Lorsque le résultat est atteint, null est renvoyé directement.

Future propose trois fonctions :
  1. pour déterminer si la tâche est terminée

  2. pour ; pouvoir interrompre la tâche ;

  3. peut obtenir les résultats de l'exécution de la tâche.

    Parce que Future n'est qu'une interface, elle ne peut pas être utilisée directement pour créer des objets, il y a donc la FutureTask suivante.

    FutureTask

    FutureTask implémente l'interface RunnableFuture La définition de cette interface est la suivante :
public interface RunnableFuture<V> extends Runnable, Future<V> {  
    void run();  
}

Vous pouvez voir que cette interface implémente. Runnable et Future Interface, l'implémentation spécifique dans l'interface est implémentée par FutureTask. Les deux méthodes de construction de cette classe sont les suivantes :

public FutureTask(Callable<V> callable) {  
        if (callable == null)  
            throw new NullPointerException();  
        sync = new Sync(callable);  
    }  
    public FutureTask(Runnable runnable, V result) {  
        sync = new Sync(Executors.callable(runnable, result));  
    }

如上提供了两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性(因为它实现了Runnable接口),把任务写成Callable,然后封装进一个由执行者调度并在必要时可以取消的FutureTask。

FutureTask可以由执行者调度,这一点很关键。它对外提供的方法基本上就是Future和Runnable接口的组合:get()、cancel、isDone()、isCancelled()和run(),而run()方法通常都是由执行者调用,我们基本上不需要直接调用它。

FutureTask的例子
public class MyCallable implements Callable<String> {  
    private long waitTime;   
    public MyCallable(int timeInMillis){   
        this.waitTime=timeInMillis;  
    }  
    @Override  
    public String call() throws Exception {  
        Thread.sleep(waitTime);  
        //return the thread name executing this callable task  
        return Thread.currentThread().getName();  
    }  

}
public class FutureTaskExample {  
     public static void main(String[] args) {  
        MyCallable callable1 = new MyCallable(1000);                       // 要执行的任务  
        MyCallable callable2 = new MyCallable(2000);  

        FutureTask<String> futureTask1 = new FutureTask<String>(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象  
        FutureTask<String> futureTask2 = new FutureTask<String>(callable2);  

        ExecutorService executor = Executors.newFixedThreadPool(2);        // 创建线程池并返回ExecutorService实例  
        executor.execute(futureTask1);  // 执行任务  
        executor.execute(futureTask2);    

        while (true) {  
            try {  
                if(futureTask1.isDone() && futureTask2.isDone()){//  两个任务都完成  
                    System.out.println("Done");  
                    executor.shutdown();                          // 关闭线程池和服务   
                    return;  
                }  

                if(!futureTask1.isDone()){ // 任务1没有完成,会等待,直到任务完成  
                    System.out.println("FutureTask1 output="+futureTask1.get());  
                }  

                System.out.println("Waiting for FutureTask2 to complete");  
                String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);  
                if(s !=null){  
                    System.out.println("FutureTask2 output="+s);  
                }  
            } catch (InterruptedException | ExecutionException e) {  
                e.printStackTrace();  
            }catch(TimeoutException e){  
                //do nothing  
            }  
        }  
    }  
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer