Bonjour,
Je suis en train d'écrire une librairie permettant d'échanger des objets java entre deux programmes (utilisant nio). Dans l'ensemble la librairire arrive à la fin de son cycle de développement mais il me reste une synchronisation à m'occuper.
Voici le contexte: admettons les deux méthodes suivantes
La méthode stop() arrete le service et rends la main une fois complètement arreté.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 /** Arrette le service courant */ public void stop(); /** Emet un objet sur le canal spécifié */ public void write(Object o,Channel c);
1. Il est illégal d'appeler une méthode write() pendant la phase d'arrêt
2. La phase d'arret s'assure qu'aucun thread n'est en cours de write avant de s'executer (laisse se complèter les tâches en cours)
A la vue de la sémantique de ces deux méthodes, l'objectif est d'essayer d'avoir le moins de contention dans la méthode write() (car elle est appelées souvents) pour gérer un cas qui arrive peu fréquemment(l'arret du service)
1ere solution:
Cette solution est la plus simple mais la méthode write() acquiert deux fois le même moniteur uniquement pour gérer la synchronisation avec la méthode stop() ce qui me semble assez inefficace.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 private Object LOCK = new Object(); private boolean running = true; private int op = 0; public void stop() { synchronized(LOCK) { this.running = false; while( op > 0 ) { try { LOCK.wait(); } catch(Exception e) { /* do nothing */ } } } // ****** // DO JOB // ****** } public void write(...) { synchronized(LOCK) { if( ! this.running ) throw new IllegalStateException("service unavailable"); op++; } // ****** // DO JOB // ****** synchronized(LOCK) { op--; if( !this.running && op == 0 ) LOCK.notifyAll(); } }
La deuxieme solution tends a rendre moins efficace la méthode stop() au profit de la méthode write()
La deuxieme solution permet à la méthode write() de ne pas effectuer de synchronisation et de ne pas créer un goulet d'étranglement entre les differents threads effectuant des write(). La contre-partie est de ne pas disposer de notification dans la méthode stop() et donc de devoir effectuer des wait() a durée limitée pour re-tester l'état.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 private static final int THRESHOLD = 1000000; private AtomicInteger op = new AtomicInteger(1); public void stop() { synchronized(this) { op.addAndGet(THRESHOLD); while( op.get() > THRESHOLD ) { try { this.wait(100); } catch(Exception e) { /* do nothing */ } } } // ****** // DO JOB // ****** } public void write(Object o) { int value = op.incrementAndGet(); if( value >= THRESHOLD ) throw new IllegalStateException("service unavailable"); // ****** // DO JOB // ****** op.decrementAndGet(); }
Ma Question:
En fait il s'agit plutôt d'une discussion ouverte quand à la solution à adopter !!La solution 2 est elle juste et surtout plus efficace que la 1ère ?
Quelle est votre opinon, avez vous une meilleure solution ?
Partager