Olá meus caros amigos. Estou com um desafio muito interessante dado pelo meu professor em uma cadeira de processamento paralelo na faculdade. Segundo ele, é um problema bastante conhecido no meio da computação quando se fala no uso de threads e multiprocessamento. O enunciado é o seguinte:
“O problema é
basicamente composto por dez elfos, nove renas e pelo Papai Noel. A vida do Papai
Noel se resume a dormir até que ele seja acordado pelas nove renas ou por um grupo
de três elfos. Caso seja acordado pelas renas, o Papai Noel as amarra ao trenó, distribui
brinquedos, desamarra-as e volta a dormir. Caso seja acordado pelos elfos, o Papai
Noel discute projetos de brinquedos e volta a dormir. A vida de uma rena se resume a
entregar presentes e tirar férias até o próximo ano. A vida de um elfo se resume a
fabricar brinquedos e se reunir com o Papai Noel. Papai Noel dorme em sua casa no
Polo Norte, e só pode ser despertado por 9 renas (todas), quando estão voltando de
suas férias de alguma ilha tropical, ou por alguns elfos, que estão tendo dificuldades em
fazer os brinquedos. O problema de um elfo nunca é grave o suficiente para acordar o
Papai Noel (caso contrário, ele pode nunca conseguir dormir), então, os elfos visitam o
Papai Noel em um grupo de três. Quando os três elfos tem seus problemas resolvidos,
qualquer outro elfo que deseje visitar o Papai Noel deve esperar que os elfos retornem.
Se o Papai Noel acordar e encontrar três elfos esperando na porta de sua loja, junto
com a última rena voltando dos trópicos, o Papai Noel decide que os elfos podem
esperar até depois do Natal, porque é mais importante preparar seu trenó assim que
que possível. Supõe-se que as renas não querem deixar as férias, portanto, ficam lá até
o último momento possível.”
Segue o código de uma solução que alcancei:
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
public class PapaiNoel {
private static Random numeroAleatorio = new Random();
private final Semaphore atencaoDoPapaiNoel;
private final Semaphore filaDeElfos;
private final CyclicBarrier tresElfos;
private final CyclicBarrier noveRenas;
private final CyclicBarrier treno;
private final CyclicBarrier problemaResolvido;
private final static int numeroDeRenas = 9;
private final static int numeroDeElfos = 10;
private final static int elfosParaAcordar = 3;
private final static int ultimaRena = 0;
private final static int terceiroElfo = 0;
private PapaiNoel () {
atencaoDoPapaiNoel = new Semaphore(1, true);
filaDeElfos = new Semaphore(elfosParaAcordar, true);
tresElfos = new CyclicBarrier(elfosParaAcordar, new Mensagem("> " + elfosParaAcordar + " elfos precisam de ajuda!"));
noveRenas = new CyclicBarrier(numeroDeRenas, () -> System.out.println(">>> Todas as renas em casa para a entrega!!"));
treno = new CyclicBarrier(numeroDeRenas, new Amarracao());
problemaResolvido = new CyclicBarrier(elfosParaAcordar, new Mensagem("> Elfos de volta ao trabalho..."));
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < numeroDeElfos; i++) {
threads.add(new Thread(new Elfo(i)));
}
for (int i = 0; i < numeroDeRenas; i++) {
threads.add(new Thread(new Rena(i)));
}
System.out.println("<--------- INÍCIO --------->");
for (Thread t : threads) {
t.start();
}
}
static class Mensagem implements Runnable {
String texto;
Mensagem(String texto) {
this.texto = texto;
}
@Override
public void run() {
System.out.println(texto);
}
}
static class Amarracao implements Runnable {
boolean trenoPreparado;
Amarracao() {
trenoPreparado = false;
}
@Override
public void run() {
trenoPreparado = !trenoPreparado;
if (trenoPreparado) {
System.out.println(">>> Renas amarradas e prontas!");
} else {
System.out.println(">>> Entrega realizada, renas desamarradas.\n Férias das renas iniciadas!");
}
}
}
class Elfo implements Runnable {
int id;
Elfo(int id) {
this.id = id;
}
@Override
public void run() {
try {
Thread.sleep(numeroAleatorio.nextInt(3000));
while (true) {
filaDeElfos.acquire();
System.out.println("> Elfo " + id + " está com problemas...");
int elfo = tresElfos.await();
if (elfo == terceiroElfo) {
System.out.println("> Papai Noel está ajudando os elfos...");
atencaoDoPapaiNoel.acquire();
}
Thread.sleep(numeroAleatorio.nextInt(1000));
System.out.println("> Problema do elfo " + id + " resolvido!");
problemaResolvido.await();
if (elfo == terceiroElfo) {
atencaoDoPapaiNoel.release();
}
filaDeElfos.release();
Thread.sleep(numeroAleatorio.nextInt(2500));
}
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Rena implements Runnable {
int id;
Rena(int id) {
this.id = id;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(4000 + numeroAleatorio.nextInt(500));
System.out.println("> Rena " + id + " voltou de suas férias no Caribe.");
int rena = noveRenas.await();
if (rena == ultimaRena) {
atencaoDoPapaiNoel.acquire();
System.out.println(">>> Entrega de Natal iniciando...");
}
treno.await();
Thread.sleep(numeroAleatorio.nextInt(150));
rena = treno.await();
if (rena == ultimaRena) {
atencaoDoPapaiNoel.release();
System.out.println(">>> Todos os brinquedos foram entregues!!!");
}
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new PapaiNoel();
}
}
Na última aula, meu professor comentou que seriam necessárias vinte threads no mínimo. Essa solução utiliza dezenove (dez elfos e nove renas). Como posso fazer com que a solução tenha o Papai Noel como mais uma thread? Eu gostaria que fosse assim para ter um maior controle da prioridade das renas sobre os elfos, e talvez colocar um tempo que o Papai Noel levaria para acordar e ir até a porta de sua loja (?). Se eu colocar o Papai Noel como Runnable também, o que ele vai fazer? O que vai ter nessa thread? Tô meio perdido hahaha