exclusão mutua utilizando semáforos

Boa noite!
Estou com um problema para sincronizar o acesso a uma região critica utilizando semáforos.
Vou explicar melhor o problema:
existe uma jaula que só pode ser usada por gorilas (no máximo 3 ao mesmo tempo) OU por babuínos (no máximo 5 ao mesmo tempo).
eu gero diversas threads do tipo babuíno e do tipo gorila e tento entrar na jaula, porém não estão entrando babuínos ou estão entrando os dois juntos (o que não pode)

segue o código:
main:

 public static void main(String[] args) {
        int i;
        int totalGorilaJaula = 3;
        int totalBabuinoJaula = 5;
        int numThreads = 10;
        Semaphore semaforoGorila = new Semaphore(totalGorilaJaula);
        Semaphore semaforoBabuino = new Semaphore(totalBabuinoJaula);
        Semaphore semaforoJaula = new Semaphore(1);
        
        Jaula jaula = new Jaula();
        
        Gorilas[] Gorila = new Gorilas[numThreads];
        Babuinos[] Babuino = new Babuinos[numThreads];
        
        
        for(i=0; i < numThreads; i++){
            Gorila[i] = new Gorilas(i, semaforoGorila,semaforoJaula, jaula);           
            Babuino[i] = new Babuinos(i, semaforoBabuino, semaforoJaula, jaula);
            Babuino[i].start();
            Gorila[i].start();
        }
    }

gorila:

public class Gorilas extends Thread {
    private int idThread;
    private Semaphore semaforoGorila; // controla quantos gorilas tem na jaula
    private Semaphore semaforoJaula;
    private Jaula jaula;
    
    public Gorilas(int id, Semaphore semaforo, Semaphore sem, Jaula jaula){
        this.idThread = id;
        this.semaforoGorila = semaforo;
        semaforoJaula = sem;
        this.jaula = jaula;
    }
    
   
    
    private void entrarJaula(){
        System.out.println("Gorila" + " " + idThread + " " + " ENTROU");
       try{
            Thread.sleep(1000);
        }
        catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("Gorila" + " " + idThread + " " + " SAIU");
    }
    
    public void run(){
        try
        {   
            if(jaula.getGorila()){ // verifica se pode entrar
                semaforoJaula.acquire();
                jaula.setBabuino(false);
                semaforoGorila.acquire();
                entrarJaula();
                
            }
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        finally{
            semaforoGorila.release();
            jaula.setBabuino(true);
            semaforoJaula.release();
           }
    }
}

Babuíno:

public class Babuinos extends Thread {
    private int idThread;
    private Semaphore semaforoBabuino; // controla quantos babuinos tem na jaula
    private Semaphore semaforoJaula;
    private Jaula jaula;
   
    
    public Babuinos(int id, Semaphore semaforo, Semaphore sem, Jaula jaula){
        this.idThread = id;
        this.semaforoBabuino = semaforo;
        semaforoJaula = sem;
        this.jaula = jaula;
    }
 
    
    private void entrarJaula(){
        System.out.println("Babuino " + idThread + " ENTROU");
       try{
            Thread.sleep(1000);
        }
        catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("Babuino " + idThread + " SAIU");
    }
    
    public void run(){
        try
        {
           if(jaula.getBabuino()){ // verifica se pode entrar
               System.out.println("entrou no babuino!!!");
                semaforoJaula.acquire();
                jaula.setGorila(false);
                semaforoBabuino.acquire();
                entrarJaula();
           }
        }            
        
        catch(InterruptedException e){
            e.printStackTrace();
        }
        finally{
            semaforoBabuino.release();
            jaula.setGorila(true);
            jaula.setBabuino(false);
            semaforoJaula.release();
        }
    }
}

Jaula:

public class Jaula{
   
   private boolean gorila = true;
   private boolean babuino = true;
   
   public  synchronized void setGorila(boolean set){
      // System.out.println("setou gorila " + set);
       gorila = set;
   }
   public synchronized void setBabuino(boolean set){
       //System.out.println("setou babuino " + set);
       babuino = set;
   }
   
   public synchronized boolean getGorila()
   {
       return gorila;
   }
   
   public synchronized boolean getBabuino()
   {
      return babuino;
   }
}

o problema provavelmente esta na lógica da jaula, mas não sei como resolver!
help!!