Table of Contents

Έτοιμα εργαλεία συγχρονισμού στο πακέτο java.util.concurrent & java.util.concurrent.locks

Το πακέτο java.util.concurrent παρέχει κάποια έτοιμα εργαλεία συγχρονισμού μεταξύ νημάτων στην java. Τα βασικά εργαλεία είναι τα εξής:

Το interface BlockingQueue

Ένα blocking queue είναι μία ουρά μηνυμάτων (queue) στην οποία μπορούν να γράφουν ή να διαβάζουν από αυτή με ασφάλεια δύο ή περισσότερα νήματα. Όταν η ουρά είναι άδεια και ένα νήμα επιχειρήσει να διαβάσει αυτό μπλοκάρει μέχρι κάποιο άλλο νήμα να γράψει στην ουρά. Αντίστοιχα, όταν ένα νήμα επιχειρεί να γράψει σε μία γεμάτη ουρά το νήμα μπλοκάρει μέχρι να ελευθερωθεί μία θέση στην ουρά μηνυμάτων από κάποιο άλλο νήμα που διάβασε. Στο παρακάτω σχήμα βλέπετε την σχηματική αναπαράσταση ενός blocking queue.

Οι βασικές μέθοδοι που υποστηρίζονται από ένα blocking queue είναι οι εξής:

Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e, time, unit)
Remove remove() poll() take() poll(time, unit)
Examine element() peek() not applicable not applicable

Όλες οι παραπάνω μέθοδοι εξασφαλίζουν ότι μόνο ένα νήμα θα προσπελάσει τα κρίσιμα τμήματα κώδικα της δομή blocking queue (thread-safe), χωρίς όμως να μπορούν να προδιαγράψουν τη σειρά εκτέλεσης των νημάτων.

Υλοποιήσεις του interface Blocking Queue:

Semaphore

Στο πακέτο java.util.concurrent υλοποιείται η κλάση του σηματοφορέα έτοιμη προς χρήση. Οι βασικές μέθοδοι για τον σηματοφορέα είναι:

Νήματα που αναμένουν ένα ή περισσότερους πόρους του σηματοφορέα και μπορούν να ικανοποιηθούν από την απελευθέρωση πόρων ξυπνούν και χρονοπρογραμματίζεται η εκτέλεση τους.

Άλλες χρήσιμες μέθοδοι είναι:

Lock

To interface java.util.concurrent.locks.Lock προδιαγράφει μία κλειδαριά, η οποία επιτρέπει μόνο σε ένα νήμα κάθε φορά να την κλειδώσει. Όλα τα νήματα που δεν καταφέρνουν να κλειδώσουν παραμένουν ανενεργά μέχρι η κλειδαριά να ξεκλειδώσει. Οι βασικές μέθοδοι που προδιαγράφει το συγκεκριμένο interface είναι οι εξής:

Υλοποίηση του παραπάνω interface είναι η κλάση java.util.concurrent.locks.ReentrantLock, η οποία επιτρέπει το πολλαπλό κλείδωμα της κλειδαριάς από το ίδιο νήμα. Το ξεκλείδωμα της κλειδαριάς πραγματοποιείται μόνον εφόσον το νήμα που κλείδωσε ξεκλειδώσει τόσες φορές όσες έχει προηγούμενα κλειδώσει. Η συγκεκριμένη κλάση δίνει την δυνατότητα του ισότιμου χρονοπρογραμματισμού των νημάτων που περιμένουν, εφόσον κληθεί ο κατασκευαστής με όρισμα true.

ReadWriteLock

Το interface ReadWriteLock προδιαγράφει δύο κλειδαριές, μία για διάβασμα και μία για γράψιμο. Η διαφορά με την προηγούμενη κλειδαριά είναι ότι την κλειδαριά που επιτρέπει το διάβασμα μπορούν να την κλειδώσουν παράλληλα πολλά νήματα που θέλουν να διαβάσουν εάν δεν υπάρχει νήμα που θέλει να γράψει. Αντίστοιχα την κλειδαριά που επιτρέπει το γράψιμο μπορεί να την κλειδώσει μόνο ένα νήμα και παράλληλα απαγορεύεται η πρόσβαση στην κλειδαριά που επιτρέπει το διάβασμα. Συνοπτικά:

Το παραπάνω interface υλοποιείται μεσω της κλάσης |java.util.concurrent.locks.ReentrantReadWriteLock. Η κλάση αυτή περιέχει δύο άλλες εσωτερικές κλάσεις την ReentrantReadWriteLock.ReadLock και ReentrantReadWriteLock.WriteLock. Η πρώτη χρησιμοποιείται για διάβασμα και η δεύτερη για γράψιμο.

Atomic Integer, Long, Boolean, Reference

Στο πακέτο java.util.concurrent.atomic η γλώσσα παρέχει ισοδύναμους των βασικών τύπων δεδομένων οι οποίοι όμως μπορούν να προσπελαστούν από δύο ή περισσότερα νήματα χωρίς να προκύψει ασάφεια ως προς την τιμή τους. Οι τύποι αυτοί είναι οι εξής:

Οι βασικές μέθοδοι που διαθέτουν οι παραπάνω κλάσεις είναι οι εξής: