Semaphore
fa acquisire tutti i permessi in una volta, altrimenti non sarebbe un vero semaphore. MA: anche la versione Java ha una coda di attesa interna. E il comportamento di tale coda è NONserve il miglior adattamento delle risorse attualmente libere ma più o meno raccogliere i permessi fino a quando la richiesta del primo nella coda può essere consentita. Ma prima che un thread immetta in coda, viene eseguito un controllo se i permessi disponibili consentono al thread di evitare di entrare nella coda.
ho modificato il codice per dimostrare che il comportamento di coda:
import java.util.concurrent.*;
public class SemaphoreTest{
static Semaphore s = new Semaphore(0);
public void fun(final char c, final int r) throws Exception {
new Thread(new Runnable(){
public void run(){
try{
System.out.println("acquire "+r);
s.acquire(r);
System.out.println(c+"_"+r);
} catch(Exception e){ e.printStackTrace(); }
}
}).start();
Thread.sleep(500);
}
public static void main(String[]args) throws Exception{
SemaphoreTest f = new SemaphoreTest();
f.fun('B',2);
f.fun('F',6);
f.fun('A',1);
f.fun('C',3);
f.fun('D',4);
f.fun('E',5);
while(s.hasQueuedThreads()){
Thread.sleep(1000);
System.out.println("release "+1+", available "+(s.availablePermits()+1));
s.release(1);
}
}
}
Fondamentalmente sono state fatte le seguenti modifiche:
- Inizia con 0 permessi - permettere a nessuno di entrare per primo nella coda.
- "Definisci" l'ordine di accodamento assegnando ogni thread a 500 ms dopo
Thread.start
.
- Ogni thread chiamerà
acquire
ma non release
.
- Il filo principale alimenterà il semaforo lentamente con un permesso dopo l'altro.
Questo darà questa uscita deterministico:
acquire 2
acquire 6
acquire 1
acquire 3
acquire 4
acquire 5
release 1, available 1
release 1, available 2
B_2
release 1, available 1
release 1, available 2
release 1, available 3
release 1, available 4
release 1, available 5
release 1, available 6
F_6
release 1, available 1
A_1
release 1, available 1
release 1, available 2
release 1, available 3
C_3
release 1, available 1
release 1, available 2
release 1, available 3
release 1, available 4
D_4
release 1, available 1
release 1, available 2
release 1, available 3
release 1, available 4
release 1, available 5
E_5
release 1, available 1
che significa: Ogni thread è risvegliato, se
- è alla testa della coda.
- sufficienti permessi sono stati accumulati.
Questo lo aggiusta, ma mi chiedo perché sia necessario. Se è bloccato dopo aver stampato B_2 e nel thread principale, dopo un po 'di tempo, stampo il numero di permessi disponibili, stampa 3. Quindi, perché il thread C non può continuare? – Vlad
@Vlad: La mia ipotesi è che il '3' non riflette il fatto che' D' potrebbe avere già "riservato" alcuni permessi per la sua chiamata 'acquire (4)'. – NPE
Penso che potresti avere ragione. Non avevo letto abbastanza attentamente la documentazione per il rilascio. [Link] (http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Semaphore.html#release (int)). Avevo dato per scontato che l'implementazione sarebbe passata in rassegna i thread e provare a trovarne una che potesse effettivamente svegliarsi. – Vlad