Kiedy uczyłem się o zatrzaskach i cyklicznych barierach, wymyśliłem te metafory.
cykliczne bariery : Wyobraź sobie, że firma ma salę konferencyjną. Aby rozpocząć spotkanie, pewna liczba uczestników spotkania musi przyjść na spotkanie (aby było ono oficjalne). poniżej znajduje się kod zwykłego uczestnika spotkania (pracownika)
class MeetingAtendee implements Runnable {
CyclicBarrier myMeetingQuorumBarrier;
public MeetingAtendee(CyclicBarrier myMileStoneBarrier) {
this.myMeetingQuorumBarrier = myMileStoneBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " i joined the meeting ...");
myMeetingQuorumBarrier.await();
System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("Meeting canceled! every body dance <by chic band!>");
}
}
}
pracownik dołącza do spotkania, czeka, aż inni przyjdą, aby rozpocząć spotkanie. też wychodzi, jeśli spotkanie zostanie odwołane :) wtedy mamy SZEFA, jak dawki nie lubią czekać, aż pojawią się inni, a jeśli straci pacjenta, odwołuje spotkanie.
class MeetingAtendeeTheBoss implements Runnable {
CyclicBarrier myMeetingQuorumBarrier;
public MeetingAtendeeTheBoss(CyclicBarrier myMileStoneBarrier) {
this.myMeetingQuorumBarrier = myMileStoneBarrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "I am THE BOSS - i joined the meeting ...");
//boss dose not like to wait too much!! he/she waits for 2 seconds and we END the meeting
myMeetingQuorumBarrier.await(1,TimeUnit.SECONDS);
System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("what WHO canceled The meeting");
} catch (TimeoutException e) {
System.out.println("These employees waste my time!!");
}
}
}
W normalnym dniu pracownik przychodzi na spotkanie, czeka na pojawienie się innego, a jeśli niektórzy uczestnicy nie przychodzą, muszą czekać bez końca! na jakimś specjalnym spotkaniu szef przychodzi i nie lubi czekać. (5 osób musi zacząć spotkanie, ale przychodzi tylko szef i entuzjastyczny pracownik), więc odwołuje spotkanie (ze złością)
CyclicBarrier meetingAtendeeQuorum = new CyclicBarrier(5);
Thread atendeeThread = new Thread(new MeetingAtendee(meetingAtendeeQuorum));
Thread atendeeThreadBoss = new Thread(new MeetingAtendeeTheBoss(meetingAtendeeQuorum));
atendeeThread.start();
atendeeThreadBoss.start();
Wynik:
//Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// These employees waste my time!!
// Meeting canceled! every body dance <by chic band!>
Istnieje inny scenariusz, w którym inny wątek z zewnątrz (trzęsienie ziemi) odwołuje spotkanie (metoda resetowania połączenia). w tym przypadku wszystkie oczekujące wątki zostaną obudzone przez wyjątek.
class NaturalDisasters implements Runnable {
CyclicBarrier someStupidMeetingAtendeeQuorum;
public NaturalDisasters(CyclicBarrier someStupidMeetingAtendeeQuorum) {
this.someStupidMeetingAtendeeQuorum = someStupidMeetingAtendeeQuorum;
}
void earthQuakeHappening(){
System.out.println("earth quaking.....");
someStupidMeetingAtendeeQuorum.reset();
}
@Override
public void run() {
earthQuakeHappening();
}
}
uruchomiony kod spowoduje zabawne wyjście:
// Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// earth quaking.....
// what WHO canceled The meeting
// Meeting canceled! every body dance <by chic band!>
Możesz także dodać sekretarkę do pokoju konferencyjnego, jeśli odbędzie się spotkanie, będzie dokumentować wszystko, ale nie jest częścią spotkania:
class MeetingSecretary implements Runnable {
@Override
public void run() {
System.out.println("preparing meeting documents");
System.out.println("taking notes ...");
}
}
Zamki : jeśli wściekły szef chce zorganizować wystawę dla klientów firmy, wszystko musi być gotowe (zasoby). tworzymy listę rzeczy do zrobienia, każdy pracownik (Thread) dozuje swoją pracę i sprawdzamy listę rzeczy do zrobienia (jedni malują, inni przygotowują nagłośnienie ...). Kiedy wszystkie pozycje na liście zadań są kompletne (zasoby są dostępne), możemy otworzyć drzwi klientom.
public class Visitor implements Runnable{
CountDownLatch exhibitonDoorlatch = null;
public Visitor (CountDownLatch latch) {
exhibitonDoorlatch = latch;
}
public void run() {
try {
exhibitonDoorlatch .await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("customer visiting exebition");
}
}
A jak robotnicy przygotowują wystawę:
class Worker implements Runnable {
CountDownLatch myTodoItem = null;
public Worker(CountDownLatch latch) {
this.myTodoItem = latch;
}
public void run() {
System.out.println("doing my part of job ...");
System.out.println("My work is done! remove it from todo list");
myTodoItem.countDown();
}
}
CountDownLatch preperationTodoList = new CountDownLatch(3);
// exhibition preparation workers
Worker electricalWorker = new Worker(preperationTodoList);
Worker paintingWorker = new Worker(preperationTodoList);
// Exhibition Visitors
ExhibitionVisitor exhibitionVisitorA = new ExhibitionVisitor(preperationTodoList);
ExhibitionVisitor exhibitionVisitorB = new ExhibitionVisitor(preperationTodoList);
ExhibitionVisitor exhibitionVisitorC = new ExhibitionVisitor(preperationTodoList);
new Thread(electricalWorker).start();
new Thread(paintingWorker).start();
new Thread(exhibitionVisitorA).start();
new Thread(exhibitionVisitorB).start();
new Thread(exhibitionVisitorC).start();