Interface Java Callable para alcançar a maneira multiencadeada


Antes do Java 1.5, há duas maneiras de criar encadeamentos, um é herdar diretamente o encadeamento e o outro é implementar a interface Runnable. Independentemente do formato usado para implementar o multithreading, precisamos chamar o método start na classe Thread para solicitar io, cup e outros recursos do sistema operacional. Como o método de execução do encadeamento não tem valor de retorno, se você precisar obter o resultado da execução, deverá obter o efeito por meio de variáveis ​​compartilhadas ou pelo uso da comunicação do encadeamento, o que é mais problemático de usar.

Desde o Java 1.5, Callable e Future foram fornecidos, através dos quais você pode obter os resultados da execução da tarefa após a conclusão da tarefa.

Introdução ao Callable e ao Futuro

A interface Callable representa um pedaço de código que pode chamar e retornar resultados; a interface Future representa uma tarefa assíncrona, que é o resultado futuro fornecido por uma tarefa que ainda não foi concluída. Portanto, Callable é usado para produzir resultados e Future é usado para obter resultados.

A interface Callable usa genéricos para definir seu tipo de retorno. A classe Executors fornece alguns métodos úteis para executar tarefas dentro de Callable no pool de threads. Como as tarefas Callable são paralelas (paralelo significa que o todo parece paralelo, de fato, apenas um encadeamento está sendo executado em um determinado momento), precisamos aguardar o resultado que ele retorna. O objeto java.util.concurrent.Future resolve esse problema para nós. Após enviar a tarefa Callable no pool de threads, um objeto Future é retornado.Você pode usá-lo para conhecer o status da tarefa Callable e obter o resultado da execução retornado pelo Callable. Future fornece o método get () para que possamos aguardar o término da chamada e obter seu resultado de execução.

Callable 与 Runnable

java.lang.Runnable, é uma interface e apenas um método run () é declarado nela:

public interface Runnable {

    public abstract void run();

}复制代码

  Como o valor de retorno do método run () é do tipo nulo, nenhum resultado pode ser retornado após a execução da tarefa.

  Callable está localizado no pacote java.util.concurrent.Também é uma interface, e apenas um método é declarado nele, mas esse método é chamado 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;
}复制代码

  Como você pode ver, essa é uma interface genérica e o tipo retornado pela função call () é o tipo V passado.

Então, como usar o Callable?

Geralmente, é usado em conjunto com o ExecutorService.Várias versões sobrecarregadas do método submit são declaradas na interface ExecutorService:

<T> Future<T> submit(Callable<T> task);

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

Future<?> submit(Runnable task);复制代码

Futuro

  Futuro é cancelar o resultado da execução da tarefa Runnable ou Callable específica, verificar se a consulta foi concluída e obter o resultado. Se necessário, você pode obter o resultado da execução através do método get, que será bloqueado até que a tarefa retorne o resultado.

  A classe Future está localizada no pacote java.util.concurrent, que é uma interface:

<T> Future<T> submit(Callable<T> task);

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

Future<?> submit(Runnable task);复制代码

Cinco métodos são declarados na interface Future. A seguir, é apresentada a função de cada método:

O método cancel é   usado para cancelar a tarefa e retorna true se a tarefa for cancelada com êxito e false se a tarefa for cancelada. O parâmetro mayInterruptIfRunning indica se é permitido cancelar a tarefa que está sendo executada mas não concluída.Se definido como true, significa que a tarefa no processo de execução pode ser cancelada. Se a tarefa foi concluída, independentemente de mayInterruptIfRunning ser verdadeiro ou falso, esse método deve retornar false, ou seja, se a tarefa cancelada for cancelada, retornará false; se a tarefa estiver sendo executada, se mayInterruptIfRunning estiver configurado como true, retorne true, se mayInterruptIfRunning estiver definido como false , Ele retorna false; se a tarefa não tiver sido executada, ela retornará true, independentemente de mayInterruptIfRunning ser verdadeiro ou falso.

O método isCancelled   indica se a tarefa foi cancelada com êxito e retorna true se a tarefa foi cancelada com sucesso antes que a tarefa fosse concluída normalmente.

O método isDone   indica se a tarefa foi concluída; se a tarefa for concluída, ela retornará verdadeiro;

O método get () é    usado para obter o resultado da execução, bloqueando e aguardando a conclusão da tarefa antes de retornar;

get (timeout longo, unidade TimeUnit) é    usado para obter o resultado da execução.Se o resultado não for obtido dentro do tempo especificado, ele retornará nulo diretamente.

Em outras palavras, o Future fornece três funções:

  1) Determine se a tarefa está concluída;

  2) capacidade de interromper tarefas;

  3) Capaz de obter resultados de execução de tarefas.

Futuro é usado para representar os resultados de cálculos assíncronos. Suas classes de implementação são java.util.concurrent.FutureTask <V> e javax.swing.SwingWorker <T, V>. Se você não deseja que o thread de ramificação bloqueie o thread principal na plataforma Android e deseja obter o resultado da execução do thread de ramificação, use FutureTask .

FutureTask

A classe Java é um design de herança único.Se você implementar multithreading herdando o Thread, não poderá herdar outras classes.O uso de interfaces poderá obter melhor o compartilhamento de dados.

FutureTask implementa a interface RunnableFuture, que é definida da seguinte maneira:

public interface RunnableFuture<V> extends Runnable, Future<V> {  
    void run();  
} 复制代码

Pode-se observar que essa interface implementa as interfaces Runnable e Future, e a implementação concreta na interface é implementada pelo FutureTask. Os dois métodos de construção desta classe são os seguintes:

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));  
}复制代码

Como acima, dois construtores são fornecidos, um com Callable como parâmetro e outro com Runnable como parâmetro. A associação entre essas classes é muito flexível para o método de modelagem de tarefas, permitindo que você escreva a tarefa como Callable com base no recurso Runnable do FutureTask (porque implementa a interface Runnable) e, em seguida, encapsule-a em um agendamento que pode ser cancelado pelo executor quando necessário FutureTask.

FutureTask pode ser agendado pelo executor, o que é crítico. Os métodos que ele fornece são basicamente uma combinação de interfaces Future e Runnable: get (), cancel, isDone (), isCancelled () e run (), e o método run () geralmente é chamado pelo executor, basicamente não o fazemos Ele precisa ser chamado diretamente. A classe FutureTask também implementa a interface Runnable, para que possa ser enviada diretamente ao Thread e Executors para execução:

public class CallableAndFuture {  
        public static void main(String[] args) {  
            Callable<Integer> callable = new Callable<Integer>() {  
                public Integer call() throws Exception {  
                    return new Random().nextInt(100);  
                }  
            }; 

        FutureTask<Integer> future = new FutureTask<Integer>(callable);  
        new Thread(future).start();  
 
        try {  
            Thread.sleep(5000);// 可能做一些事情  
 
            int result = future.get());  
 
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        } catch (ExecutionException e) {  
            e.printStackTrace();  
        }  
    }  
} 复制代码

public class CallableAndFuture {  
    public static void main(String[] args) { 
 
        //ExecutorService.submit()
        ExecutorService threadPool = Executors.newSingleThreadExecutor();  
        Future<Integer> future = threadPool.submit(new Callable<Integer>() {  
            public Integer call() throws Exception {  
                return new Random().nextInt(100);  
            }  
        }); 
 
        try {  
            Thread.sleep(5000);// 可能做一些事情  
 
            int result = future.get()); //Future.get()
 
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        } catch (ExecutionException e) {  
            e.printStackTrace();  
        }  
    }  复制代码

Se você deseja executar várias tarefas com valores de retorno e obter vários valores de retorno, é possível usar CompletionService :

CompletionService é equivalente a Executor mais BlockingQueue.O cenário de uso é que, quando o thread filho executa simultaneamente uma série de tarefas, o thread principal precisa recuperar o valor de retorno da tarefa do thread filho em tempo real e processar esses valores de retorno sequencialmente. Quem

public class CallableAndFuture {  
    public static void main(String[] args) {  
        ExecutorService threadPool = Executors.newCachedThreadPool();  
        CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);  
        for(int i = 1; i < 5; i++) {  
            final int taskID = i;  
            //CompletionService.submit()
            cs.submit(new Callable<Integer>() {  
                public Integer call() throws Exception {  
                    return taskID;  
                }  
            });  
        }  
        // 可能做一些事情  
        for(int i = 1; i < 5; i++) {  
            try {  
                int result = cs.take().get());  //CompletionService.take()返回Future
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            } catch (ExecutionException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}   复制代码

Ou não use CompletionService: primeiro crie uma coleção do tipo Futuro, adicione o valor de retorno da tarefa enviada pelo Executor à coleção e, finalmente, facilite a coleta para retirar os dados.

A diferença:

No método de coleta Future, a tarefa de envio não é necessariamente concluída na ordem de adicionar a lista mantida por si mesma. Cada objeto Future que estiver atravessando a lista não está necessariamente em um estado concluído, e o método get () será bloqueado neste momento.Se o sistema for projetado para que cada thread possa continuar a fazer as seguintes ações de acordo com o resultado após a conclusão Isso adicionará tempo de espera adicional aos threads que estão atrás da lista, mas que são concluídos primeiro.

A implementação do CompletionService é manter um BlockingQueue que contém objetos futuros. Somente quando o estado do objeto Futuro terminar, ele será adicionado à Fila.O método take () é realmente o Consumidor no Produtor-Consumidor. Ele pegará o objeto Future da fila e, se a fila estiver vazia, será bloqueada até que um objeto Future concluído seja adicionado à fila.

Portanto, o primeiro concluído deve ser retirado primeiro. Isso reduz o tempo de espera desnecessário.


Acho que você gosta

Origin juejin.im/post/5e9af92f6fb9a03c3a0894e8
Recomendado
Clasificación