import java.util.concurrent.atomic.AtomicBoolean; // v0.1, 25/09/20 (PM) class TamponBorné { /* * Pour simplifier la mise en œuvre du test, on se limite ici à un tampon * d'entiers */ private int taille; // nombre de cases du tampon private int nbOccupé = 0; // nombre d'items présents dans le tampon (vide initialement) private int queue = 0; // queue de file (tampon circulaire), insertions private int tête = 0; // tête de file (tampon circulaire), extractions private int trace = 0;// utile uniquement pour faciliter le test : // on va considérer qu'on dépose les valeurs successives de trace... private int[] tampon; public TamponBorné(int t) { taille = t; tampon = new int[taille]; } static AtomicBoolean occupied = new AtomicBoolean(true); synchronized public void déposer() { while (nbOccupé >= taille && !occupied.compareAndSet(false, true)) { try { System.out.println("wait prod"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // dépôt tampon[queue] = trace++; // tampon[queue] = i; queue = (queue + 1) % taille; nbOccupé++; // affichage pour le test uniquement String msg = (char) 27 + "[0;32m" + "P : " + (trace - 1); if (nbOccupé == taille) { msg = msg + " (PLEIN)"; } else { msg = msg + " (" + nbOccupé + ")"; } msg = msg + (char) 27 + "[0m"; System.out.println(msg); TAS.occupied.set(false); notifyAll(); System.out.println("notification"); } // déposer() synchronized public int retirer() { // Item remove() int i; // Item i while (nbOccupé <= 0 && !occupied.compareAndSet(false, true)) { try { System.out.println("wait conso"); this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // retrait i = tampon[tête]; tête = (tête + 1) % taille; nbOccupé--; // affichage pour le test uniquement String msg = (char) 27 + "[0;31m" + "C : " + i; if (nbOccupé == 0) { msg = msg + " (VIDE)"; } else { msg = msg + " (" + nbOccupé + ")"; } msg = msg + (char) 27 + "[0m"; System.out.println(msg); TAS.occupied.set(false); notifyAll(); System.out.println("notification"); return i; } // retirer } // TamponBorné /* ---------- inutile de modifier ce qui suit ---------- */ class Producteur implements Runnable { private TamponBorné tampon; public Producteur(TamponBorné t) { tampon = t; } public void run() { try { Thread.sleep(10); // pour le test : initialement, les consommateurs trouveront tous un tampon vide for (int i = 0; i < 25; i++) { // possible de trouver des producteurs bloqués à la fin, selon le nb de // consommateurs tampon.déposer(); Thread.sleep(2 * i); // producteurs ralentissent un peu } } catch (InterruptedException e) { System.out.println("interrompu"); } } } class Consommateur implements Runnable { private TamponBorné tampon; private int identité; public Consommateur(TamponBorné t) { tampon = t; } public void run() { int res; for (int i = 0; i < 25; i++) { // possible de trouver des consommateurs bloqués à la fin, selon le nb de // producteurs res = tampon.retirer(); try { Thread.sleep(10 * i); // consommateurs ralentissent davantage } catch (InterruptedException e) { System.out.println("interrompu"); } } } } public class ProdConso { public static void main(String[] args) { int nbProd = 5; int nbConso = 10; int tailleTampon = 10; // aucun blindage : on suppose que les valeurs de paramètres fournies sont // raisonnables if (args.length != 3) { System.out.println("java ProdConso "); System.out.println("-> choix par défaut : " + nbProd + "/" + nbConso + "/" + tailleTampon); } else { nbProd = Integer.parseInt(args[0]); nbConso = Integer.parseInt(args[1]); tailleTampon = Integer.parseInt(args[2]); } System.out.println("nbProd (arg1) : " + nbProd + " /nbConso (arg2) : " + nbConso + " /nbCases) (arg3) : " + tailleTampon + "\n"); TamponBorné t = new TamponBorné(tailleTampon); for (int i = 0; i < nbProd; i++) { new Thread(new Producteur(t)).start(); } for (int i = 0; i < nbConso; i++) { new Thread(new Consommateur(t)).start(); } // ajouter éventuellement un thread pour gérer l'arrêt et une prise de cliché // finale } }