Date post: | 05-Apr-2017 |
Category: |
Technology |
Upload: | codemotion |
View: | 24 times |
Download: | 2 times |
I processi del sistema operativo
● Istanza di programma in esecuzione
● Comunicazione limitata
● JVM è un processo, di solito
Thread nel sistema operativo
● Eseguono istruzioni in modo concorrente
● Condividono dati
Fonte immagine: wikipedia.org
Thread in Java
● Un main thread può lanciarne altri
● Istanza classe Thread
● Ogni thread ha una sua pila di chiamate
Fonte immagine: http://blog.takipi.com
Lancio di un threadpublic class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
Thread pool
● Allocare e liberare memoria degrada le prestazioni
● È meglio fare riuso di thread● Un thread usato torna nel pool● Numero di thread nel pool può essere
fisso o variabile
Interfaccia Executor
● Astrazione per la gestione dei thread pool● Unico metodo:
void execute(Runnable command);
Che ha un funzionamento simile a:
(new Thread(runnable)).start();
● Astrazione sulla gestione del thread pool
Esempio didattico di Executor
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
Executor in pratica
● Conviene delegare la gestione dei pool di thread al container
● Oppure usare ThreadPoolExecutor e ScheduledThreadPoolExecutor
Interfaccia Callable
public interface Callable<V> {
V call() throws Exception;
}
● Restituisce un valore del tipo che vogliamo noi
● Può lanciare eccezioni al chiamante
Future
● Rappresenta una computazione● Può essere in corso, eseguita o annullata● Chiamando il metodo get() metto in
waiting il thread chiamante
Interfaccia Futurepublic 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;
}
Le callback● Quando il metodo
asincrono termina, ne chiama un altro
● Metodi distinti in caso di successo o errore
Lana Turner
ListenableFuture di Spring Corepublic interface ListenableFuture<T> extends Future<T> {
void addCallback(ListenableFutureCallback<? super T> var1);
void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);
}
E se la callback dovesse chiamare un’altra callback?
● Può capitare di dover fare varie chiamate consecutive
● Se non si sta attenti, si finisce per scrivere codice difficile da modificare
Esempio in JavaListenableFuture<String> listenable = asyncService.listenableMethod(); listenable.addCallback(new ListenableFutureCallback<String>(){ public void onSuccess(String s) { try { ListenableFuture lf = asyncService.listenableMethod(); lf.addCallback(new ListenableFutureCallback() { public void onFailure(Throwable throwable) { try { ListenableFuture lf2 = asyncService.listenableMethod(); } catch (InterruptedException e) { logger.error(e.getLocalizedMessage(), e); } } public void onSuccess(Object o) { } }); } catch (InterruptedException e) { logger.error(e.getLocalizedMessage(), e); } } public void onFailure(Throwable throwable) {} });
Facciamoci aiutare da Java 8
● Ho una classe MiaClasse che ha un metodo mioMetodo()
● Posso passare questo metodo come argomento:
MiaClasse::mioMetodo
CompletableFuture di Java 8
● Passiamo i metodi come argomenti● Aggiungere callback: thenApply()
● Gestire errori: exceptionally()
● Ultimo metodo: thenAccept()
Esempio di CompletableFuture
CompletableFuture<String> completableFuture = asyncService.completableMethod();
completableFuture = completableFuture.exceptionally(this::onException);
completableFuture = completableFuture.thenApply(this::intermediateMethod);
completableFuture.thenAccept(this::lastMethod);
Altro esempio
CompletableFuture.supplyAsync(this::findReceiver)
.thenApply(this::sendMsg)
.thenAccept(this::notify);
Configurazione generale
● Da XML, dopo aver aggiunto il namespace XML “task”:
<task:annotationdriven />
● Annotation per Spring Boot:
@EnableAsync
Configurazione TaskExecutor
● Di default viene usato il SimpleAsyncTaskExecutor che non riusa i thread
● Per usare il ThreadPoolTaskExecutor:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
Esempio di Future @Async
public Future<String> futureMethod(){
Future<String> future = null;
try {
Thread.sleep(1000L);
future = AsyncResult.forValue("OK");
} catch (InterruptedException e) {
logger.error(e.getLocalizedMessage(), e);
future = AsyncResult.forExecutionException(e);
}
return future;
}
Esempio di ListenableFuture @Async
public ListenableFuture listenableMethod() throws InterruptedException {
ListenableFuture<String> listenableFuture = null;
try {
Thread.sleep(1000L);
listenableFuture = AsyncResult.forValue("OK");
} catch (InterruptedException e) {
logger.error(e.getLocalizedMessage(), e);
listenableFuture = AsyncResult.forExecutionException(e);
}
return listenableFuture;
}
Esempio di CompletableFuture @Async
public CompletableFuture<String> completableMethod() throws InterruptedException{
CompletableFuture<String> completableFuture = new CompletableFuture<String>();
try {
Thread.sleep(1000L);
completableFuture.complete("OK");
} catch (InterruptedException e) {
logger.error(e.getLocalizedMessage(), e);
completableFuture.completeExceptionally(e);
}
return completableFuture;
}
Lato Controller
● Nei vari controller, va restituito un DeferredResult o un Callable
● Il DeferredResult deve essere valorizzato nella callback
● Il Callable fa tutto nel metodo call()● Possono contenere il valore da restituire,
oppure un ModelAndView
Esempio Spring Data JPAinterface EmployeeRepository extends JpaRepository<Employee, Long> {
@Async
Future<List<Employee>> findDistinctByFirstName(String firstName);
@Async
CompletableFuture<Employee> findFirstByFirstNameIgnoreCase(String firstName);
@Async
ListenableFuture<Employee> findFirstByLastName(String lastName);
}