Если вы хотите бросить свой собственный:
private static final int MAX_WORKERS = n;
private List<Worker> workers = new ArrayList<Worker>(MAX_WORKERS);
private boolean roomLeft() {
synchronized (workers) {
return (workers.size() < MAX_WORKERS);
}
}
private void addWorker() {
synchronized (workers) {
workers.add(new Worker(this));
}
}
public void removeWorker(Worker worker) {
synchronized (workers) {
workers.remove(worker);
}
}
public Example() {
while (true) {
if (roomLeft()) {
addWorker();
}
}
}
Где Worker - ваш класс, расширяющий Thread. Каждый работник будет вызывать метод removeWorker этого класса, передавая себя в качестве параметра, когда он завершит свое дело.
С учетом сказанного, среда Executor выглядит намного лучше.
Редактировать: Кто-нибудь хочет объяснить, почему это так плохо, вместо того, чтобы просто уменьшить его?