Στόχος
1. Εξοικείωση με τα threads της Java
2. Εξοικείωση με την κλάση Threads και το interface Runnable
3. Κατανόηση του μοντέλου εκτέλεσης νημάτων της Java
4. Δημιουργία μιας εφαρμογής του προβλήματος Παραγωγού – Καταναλωτή (Producer- Consumer)
5. Χρήση κατασκευών συγχρονισμού της Java για επίλυση του προβλήματος Producer- Consumer
Προαπαιτούμενα
Για την αποτελεσματική εκτέλεση του εργαστηρίου θα πρέπει να έχετε μελετήσει την σχετική θεωρία που θα έχει παραδοθεί μέχρι την ημερομηνία εκτέλεσης του εργαστηρίου.
Δραστηριότητες άσκησης
Οι δραστηριότητες της άσκησης Producer-Consumer δίνονται στη συνέχεια με στόχο την κατανόηση των κατασκευών της Java για συγχρονισμό νημάτων.
Αν χρειάζεσθε μια γρήγορη εισαγωγή στις βασικές έννοιες του Ταυτόχρονου προγραμματισμού στην Java εκτελέστε πριν την εκτέλεση των δραστηριοτήτων της άσκησης τις παρακάτω 2 δραστηριότητες.
Δ0-1. Ανάπτυξη απλής πολύ-νηματικής εφαρμογής
1.1 Αναπτύξτε ένα πρόγραμμα που θα δημιουργεί δύο στιγμιότυπα της κλάσης PingPong όπως ορίστηκε στο μάθημα. Εκτελέστε την εφαρμογή και παρατηρήστε την συμπεριφορά του περιβάλλοντος εκτέλεσης.
1.2 Δώστε μια έκδοση αξιοποιώντας την sleep και μια χωρίς την sleep. Παρατηρήστε την συμπεριφορά του συστήματος και συσχετίσατε την με τον κύκλο ζωής νήματος (thread life cycle) της Java.
1.3 Τρέξτε την εφαρμογή σας σε debug mode στο Eclipse και παρατηρήστε τα νήματα και το interleaving.
1.4 Δώστε μια έκδοση της ίδιας εφαρμογής αξιοποιώντας το Runnable interface της Java.
Δ0-2. Αξιοποίηση των Προτεραιοτήτων των νημάτων (thread priority)
Στην εφαρμογή που ήδη αναπτύξατε δώστε διαφορετικές προτεραιότητες στα νήματα σας για να παρατηρήσετε την συμπεριφορά της JVM. Σε κάθε περίπτωση αιτιολογήστε την συμπεριφορά αυτή.
Δ1. Ανάπτυξη απλής εφαρμογής Παραγωγού - Καταναλωτή (Προβλήματα)
Δ1-1. Αναπτύξτε μια εφαρμογή η οποία θα έχει ένα νήμα που θα δρα ως παραγωγός (Producer) και ένα νήμα που θα δρα ως καταναλωτής (consumer).
Ο παραγωγός θα παράγει ένα αγαθό και θα το βάζει σε μια αποθήκη από την οποία θα το παίρνει ο καταναλωτής και θα το καταναλώνει. Στην φάση αυτή, η αποθήκη έχει μέγεθος ενός αγαθού. Ορίστε το αγαθό να αποτελείται από ένα αλφαριθμητικό και έναν ακέραιο.
Δ1-2. Διαχωρίστε τον κρίσιμο τομέα σε παραγωγό και καταναλωτή.
Στη φάση αυτή δεν έχετε πρωτόκολλα πριν και μετά, δεν χρησιμοποιείτε δηλαδή τους μηχανισμούς συγχρονισμού νημάτων που σας παρέχει η Java. Μελετήστε τη συμπεριφορά της εφαρμογής σας.
Τροποποιήστε το πρόγραμμα σας ώστε να επιδείξετε την παραβίαση του αμοιβαίου αποκλεισμού.
Δ1-3. Παρατηρήστε και απαριθμήστε τα προβλήματα που η λύση σας παρουσιάζει.
Δ1-4. Τροποποιήστε την ProducerConsumerApp ώστε να εντοπίζει τα 3 προβλήματα και να τυπώνει αντίστοιχο μήνυμα μαζί με την πληροφορία που επιδεικνύει το πρόβλημα.
Ερώτηση: Αν η μέθοδος put() της αποθήκης έχει μόνο ένα statement με το οποίο ανατίθεται η αναφορά του προϊόντος στην αποθήκη μπορούμε να παρατηρήσουμε παραβίαση του αμοιβαίου αποκλεισμού;
Αν όχι, πως πρέπει να διαμορφώσουμε την put();
Δ1-5. Προτείνατε λύσεις με παραδοσιακές τεχνικές.
Για παράδειγμα χρησιμοποιήστε μια boolean μεταβλητή την οποία θα ελέγχει και ο Παραγωγός και ο Καταναλωτής πριν μπούνε στον κρίσιμο τομέα τους.
Ελέγξατε την λύση όσον αφορά την παραβίαση του ΑΑ και την βιωσιμότητα της. Παρατηρήστε πιθανά προβλήματα. Αιτιολογήστε.
Δ2. Ανάπτυξη εφαρμογής Παραγωγού - Καταναλωτή (Λύση με αλγόριθμο Dekker)
Δ2-1. Δοκιμάστε την πρώτη από τις τέσσερις λύσεις που χρησιμοποιούμε για να φτάσουμε στον αλγόριθμο του Deker, αυτή δηλαδή που βασίζεται στην χρήση της μεταβλητής turn.
Ελέγξατε την λύση όσον αφορά την παραβίαση του ΑΑ και την βιωσιμότητα της. Παρατηρήστε πιθανά προβλήματα. Αιτιολογήστε.
Δ2-2. Δοκιμάστε τις λύσεις 2, 3 και 4. Εντοπίστε τα προβλήματα. Επιδείξτε τα.
Δ3. Ανάπτυξη εφαρμογής Παραγωγού - Καταναλωτή (Λύση με Σημαφόρους)
Χρησιμοποιήστε ως βάση το πρόγραμμα που αναπτύξατε στο βήμα Δ1-2.
Δ3-1. Χρησιμοποιήστε την κατασκευή του Σημαφόρου για να δώσετε λύση στο πρόβλημα του αμοιβαίου αποκλεισμού.
Δ3-2. Επεκτείνατε την λύση σας ώστε να δώσετε λύση και στα άλλα δύο προβλήματα του Παραγωγού – Καταναλωτή.
Δ3-3. Τροποποιήστε την εφαρμογή σας ώστε να περιλάβει σταδιακά 2 παραγωγούς και στη συνέχεια 2 καταναλωτές.
Μελετήστε τη συμπεριφορά της εφαρμογής σας. Ελέγξατε την λύση όσον αφορά την παραβίαση του ΑΑ και την βιωσιμότητα της. Παρατηρήστε πιθανά προβλήματα.
Δ4. Ανάπτυξη εφαρμογής Παραγωγού - Καταναλωτή (Λύση με Monitor)
Χρησιμοποιήστε ως βάση το πρόγραμμα που αναπτύξατε στο βήμα Δ1-2.
Δ4-1. Χρησιμοποιήστε την κατασκευή του Ελεγκτή (Monitor) για να δώσετε λύση στο πρόβλημα του αμοιβαίου αποκλεισμού. Ελέγξατε την βιωσιμότητα της λύσης σας.
Δ4-2. Τροποποιήστε την εφαρμογή σας ώστε να περιλάβει 2 παραγωγούς ή 2 καταναλωτές. Μελετήστε τη συμπεριφορά της εφαρμογής σας στην περίπτωση χρήσης του if αντί του while στον έλεγχο της condition variable. Παρατηρήστε και καταγράψατε το πρόβλημα. Αιτιολογήστε τη χρήση του while.
Μελετήστε τη συμπεριφορά της εφαρμογής σας στην περίπτωση χρήσης του notify() αντί του notifyAll(). Παρατηρήστε και καταγράψατε το πρόβλημα. Αιτιολογήστε τη χρήση του notifyAll() και καταγράψτε τα μειονεκτήματα του σε σχέση με το notify().
Δ4-3. Εκτελέστε τις ενέργειες 10.4.1 και 10.4.2 του κεφαλαίου 10 του βιβλίου Αντικειμενοστρεφής Προγραμματισμός – Java. Η άσκηση 10.5 του βιβλίου αποτελεί μια καλή εξάσκηση με το πρόβλημα του παραγωγού-καταναλωτή.