Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 97 di 134
  • livello avanzato
Indice lezioni

Programmazione concorrente

Grazie all'interfaccia Executor, da Java 1.5, è possibile gestire al meglio la concorrenza
Grazie all'interfaccia Executor, da Java 1.5, è possibile gestire al meglio la concorrenza
Link copiato negli appunti

La programmazione concorrente è sicuramente una delle migliori caratteristiche di questo linguaggio in quanto consente di avere una forma di programmazione multiprocesso "leggera", nel senso che i Thread di Java condividono lo stesso spazio di memoria e il tempo per fare il content switching (passaggio di contesto dall'esecuzione di un Thread ad un altro) è minore rispetto ai processi tradizionali. Unico neo è quello di avere la logica di business accoppiata con il ciclo di vita e quindi la logica di esecuzione dello stesso Thread.

Ora vediamo come da Java 1.5 sia possibile disaccoppiare le due cose. Le nuove interfacce e classi di Java permettono di ottenere dei servizi migliori nello sviluppo di programmi concorrenti. Una di queste è l'interfaccia Executor, il cui compito è quello di definire un flusso di esecuzione di task (thread java) e di poterne controllare la stessa esecuzione.

Attraverso l'estensione di java.util.concurrent.Executor ed ExecutorService (che ha un'interfaccia molto più fornita) possiamo definire il ciclo di esecuzione di un generico Thread ma, per gli obiettivi più comuni, utilizzeremo i metodi statici di java.util.concurrent.Executors che ci consentono l'accesso a degli Executor standard, che sono:

  • Single Thread Executor
  • Fixed Thread Executor
  • Cached Thread Executor
  • Scheduled Thread Executor

Attraverso l'uso di quest'interfaccia potremo eseguire un set fisso di thread (ad esempio un server che accetta delle connessioni) o altri interessanti combinazioni di logica con l'uso delle classi Callable e Future.

Listato 21.1. Esempio di un server che effettua un servizio tramite socket

package it.html.threads;
public class EchoServer {
  
  public static void main(String[] args) {
    ServerSocket server = null;
    
    //Avviamo il server
    try {
      server = new ServerSocket(6666);
    } catch (IOException e) {
      System.out.println("Eccezione all'avvio del server: "+e.getMessage());
      System.exit(-1);
    }
    
    //Creo un pool di thread concorrenti
    ExecutorService executor = Executors.newFixedThreadPool(5);
    
    //Aspettiamo una nuova connessione cui deleghiamo l'esecuzione
    //all'executor service definito in precedenza

    while(true){
      try{
        System.out.println("Waiting incoming connection...");
        Socket incoming = server.accept();
        executor.execute(new EchoThread(incoming));
      }catch(Exception e){
        executor.shutdown();
      }
    }
  }
}

Il main definisce un ServerSocket che attende connessioni all'infinito. Su ogni connessione creiamo un thread (che definiamo in seguito) per gestire il servizio. In precedenza avevamo definito un Executor di cinque elementi, quindi stiamo definendo una coda di esecuzione di al massimo cinque elementi da eseguire concorrentemente. Anziché effettuare l'esecuzione (con il classico metodo start()) qui deleghiamo l'esecuzione all'executor service, ignorando come questo gestisca la logica di avvio.

Nel caso avvenga un'eccezione utilizziamo il metodo shutdown() che effettua la chiusura di tutti i thread che si stanno eseguendo. Segue il codice del thread:

class EchoThread implements Runnable{
  Socket socket;
  public EchoThread(Socket socket){
    this.socket = socket;
  }
  public void run(){
    System.out.println("Incoming connection: "+socket.getInetAddress());
    //Continua con la lettura/scrittura sulla socket aperta...
  }
}

Abbiamo lasciato il servizio blank, visto che non rientra ai fini della discussione. A questo punto vediamo anche un semplice client per effettuare l'esecuzione di un thread (voi potete modificarlo aggiungendo più chiamate concorrenti).

package it.html.threads;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class EchoClient {
  /**
   * @param args
   * @throws IOException
   * @throws UnknownHostException
   */

  public static void main(String[] args) throws UnknownHostException, IOException {
    Socket socket = new Socket("127.0.0.1",6666);
    System.out.println("Connected!");
    //... fa qualcosa con lo stream
  }
}

Ti consigliamo anche