Skip to main content

Producteur Consommateur

La création d'un thread consomme une quantité importante de mémoire. Dans une application où il y a beaucoup de programmes clients, la création d'un thread par client n'évoluera pas. Ainsi, Java  a proposé un framework d'exécuteur pour fournir un pool de threads pour l'exécution limitant le nombre de threads servant la demande du client à tout moment. Cela améliore les performances et réduit les besoins en mémoire.

Java 5 fournit également des implémentations de file d'attente de blocage et nous n'avons plus besoin de contrôler les applications producteur/consommateur à l'aide de wait/notify. Ceci est automatiquement pris en charge par les implémentations de BlockingQueue.

Un exemple de producteur/consommateur utilisant une implémentation de file d'attente bloquante et un framework d'exécuteur est le suivant :


public class ProducerConsumer {

    private static final int NUM_OF_MSGS = 20;
    private static final BlockingQueue<String> queue 
                                              = new ArrayBlockingQueue<String>(5);
    private static ExecutorService producerPool = Executors.newFixedThreadPool(3);
    private static ExecutorService consumerPool = Executors.newFixedThreadPool(1);

    private static Logger logger =  Logger.getLogger(ProducerConsumer.class.getName());

    public static void main(String[] args) {
        Runnable producerTask = () -> {
            try {
                queue.put("test Message");
                System.out.println(Thread.currentThread().getName() 
                                   + " put message queue.size() " + queue.size());
            } catch (InterruptedException e) {
                logger.log(Level.SEVERE, e.getMessage(), e);
            }
        };
        Runnable consumerTask = () -> {
            try {
                System.out.println(Thread.currentThread().getName() 
                                   + " received msg " + queue.take());

            } catch (InterruptedException e) {
                logger.log(Level.SEVERE, e.getMessage(), e);
            }
        };
        try {
            for (int i = 0; i < NUM_OF_MSGS; i++) {
                producerPool.submit(producerTask);
            }
            for (int i = 0; i < NUM_OF_MSGS; i++) {
                consumerPool.submit(consumerTask);
            }
        } finally {
            if (producerPool != null) {
                producerPool.shutdown();
            }
            if (consumerPool != null) {
                consumerPool.shutdown();
            }
        }
    }

}

 

Le but de cela est de faire des opérations longues en mode asynchrone.

Ici nous avons une double queue avec une conversion HTML->PDF


public class ProducerConsumer2 {

    private static final int NUM_OF_MSGS = 20;
    private static final BlockingQueue<String> queueHtml 
                                              = new ArrayBlockingQueue<String>(5);
    private static final BlockingQueue<File> queueFile= new ArrayBlockingQueue<File>(5);
    
    private static ExecutorService consumerHtmlPool = Executors.newFixedThreadPool(4);
    private static ExecutorService consumerFilePool = Executors.newFixedThreadPool(4);

    private static Logger logger =  Logger.getLogger(ProducerConsumer2.class.getName());

    public static void main(String[] args) throws IOException {
     
        Runnable consumerTask = () -> {
            try {
                
            	String html=queueHtml.take();
            	UUID uuid=UUID.randomUUID();
            	File outputFile=new File(uuid.toString()+".pdf");
            	HtmlConverter.convertToPdf(html, new FileOutputStream(outputFile));
            	queueFile.put(outputFile);
            } catch (InterruptedException e) {
                logger.log(Level.SEVERE, e.getMessage(), e);
            } catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        };
        Runnable consumerFileTask = () -> {
            try {
                
            	File pdfFile=queueFile.take();
            	System.err.println(pdfFile.getAbsolutePath());
            } catch (InterruptedException e) {
                logger.log(Level.SEVERE, e.getMessage(), e);
            }
        };
        try {
            for (int i = 0; i < NUM_OF_MSGS; i++) {
            	consumerHtmlPool.submit(consumerFileTask);
            }
            for (int i = 0; i < NUM_OF_MSGS; i++) {
            	consumerFilePool.submit(consumerTask);
            }
            queueHtml.add("\"<h1>Hello</h1>\"\r\n"
            		+ "			+ \"<p>This was created using iText</p>\"\r\n"
            		+ "			");
            System.in.read();
        } finally {
            if (consumerHtmlPool != null) {
            	consumerHtmlPool.shutdown();
            }
            if (consumerFilePool != null) {
            	consumerFilePool.shutdown();
            }
        }
    }

}

Le pom doit être modifié ainsi:

	  <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>7.1.9</version>
        <type>pom</type>
    </dependency>

    <!-- iText pdfHTML add-on -->
    <dependency>
	    <groupId>com.itextpdf</groupId>
	    <artifactId>html2pdf</artifactId>
	    <version>2.1.6</version>
	</dependency>