Dunque.
A te serve una classe che estende Thread che rappresenta il thread che accede alla risorsa e una classe che rappresenta il "semaforo" che fa accedere il thread alla risorsa.

La classe che estende Thread deve occuparsi solo del lavoro che essa deve svolgere: accedere alla risorsa. Non si deve preoccupare di fermarsi o riattivarsi, a questo ci pensa il semaforo:
codice:
public class MioThread extends Thread {
   public MioThread(...) { ... }
   public void run() {
      // esegue le proprie azioni sulla risorsa
      risorsa.accedi();
   }
}
La classe che rappresenta il semaforo per la risorsa, invece, deve prevedere dei metodi per l'accesso da parte dei thread: saranno questi che controllano la fattibilità dell'operazione e, eventualmente, fermano il thread che ha fatto la richiesta:
codice:
public class Risorsa {
   public synchronized void accedi() {
      try {
         while (condizione_di_non_accesso) wait();
         ...  // accesso alla risorsa
         notifyAll();  // Notifico a tutti che la risorsa è disponibile
      } catch (Exception e) { e.printStackTrace();}
   }
}
Come sbloccare i thread dipende dall'applicazione. Se ad esempio ho una situazione di tipo Produttore/Consumatore l'accesso alla risorsa sarà effettuato da due Thread di tipo diverso tramite due metodi diversi. Sarà il metodo di accesso al produttore che sbloccherà i consumatori, ponendo la condizione_di_non_accesso (al consumatore) a false e richiamando notifyAll(). Viceversa, sarà il metodo di accesso al consumatore che sbloccherà il produttore ponendo la condizione di non accesso (al produttore) a false e richiamando notifyAll().


Ciao.