Aquí deixo un exemplo para o modelo usando un semáforo:
import java.security.SecureRandom;import java.util.concurrent.Semaphore;import java.util.concurrent.atomic.AtomicInteger;/** * @author snolde * */public class Tuberia { class Hilo extends Thread{ int id; public Hilo(int id){ this.id=id; } @Override public void run() { hil(id); } } static SecureRandom sr = new SecureRandom(); Semaphore guardia; AtomicInteger count = new AtomicInteger(0); public Tuberia(int limite){ guardia = new Semaphore(limite, true); } public void hil(int id){ try { guardia.acquire(); } catch (InterruptedException e) {} synchronized(count){ System.out.println(String.format("Hilo %d entró (%d)", id, count.incrementAndGet())); } try { // simulación de código productivo, carga de 500-1000 ms Thread.sleep(500+sr.nextInt(500)); } catch (InterruptedException e) {} synchronized(count){ System.out.println(String.format("Hilo %d salió (%d)", id, count.decrementAndGet())); } guardia.release(); } public void creaHilos(int num){ for (int i = 1; i<=num; i++){ new Hilo(i).start(); try { // variable Thread.sleep(10); } catch (InterruptedException e) {} } } public static void main(String args) { Tuberia tub = new Tuberia(5); tub.creaHilos(10); }}
coa clase Hilo
declarada como clase interna non é necesaria para explicar a referencia a Tuberia
porque ten acceso a os métodos da clase primaria.
O contador está incluído en bloques curtos sincronizados para garantir que os eventos sexan impresos na secuencia que se producen.
O semáforo no exemplo limita a Número de fíos que teñen acceso ao código entre acquire
e release
.
A principal diferenza entre as dúas implementacións é que, coa luz de tráfico, hai unha serie de fíos que poden acceder ao código simultaneamente mentres que o método sincronizado asegura que só un fío pode acceder a este bloque de código, converténdose nunha acción atómica.
Se isto Nin un sentido non é visible nun exemplo tan básico, sen pensar que realmente é o traballo que fan os fíos e cales son os recursos que necesitan para iso.
Para experimentar con comportamento, cambia de pausa en xeración de novos Strands, o número de fíos, a cantidade de permisos ou tempo aleatorio para a carga do código.