Во время выполнения вашего основного потока вы создаете два других потока и говорите им ждать друг друга. Но вы ничего не написали, чтобы заставить ваш главный поток ждать их и жаловаться, что это не ждет. Попробуйте
CyclicBarrier barrier = new CyclicBarrier(3);
mythread thread1 = new mythread(barrier).start();
mythread thread2 = new mythread(barrier).start();
barrier.await(); // now you wait for two new threads to reach the barrier.
System.out.println("Should wait till both threads finish executing before printing this");
КСТАТИ. Не расширяйте класс Thread, если это не нужно. Реализуйте Runnable и передайте реализации объектам Thread. Как это:
class MyRunnable implements Runnable {
public void run(){
// code to be done in thread
}
}
Thread thread1 = new Thread(MyRunnable);
thread1.start();
EDIT
Обоснование избегания расширения темы.
Эмпирическое правило - это как можно меньше связи. Наследование - это очень сильная связь между классами. Вы должны наследовать от Thread, если хотите изменить некоторые из его поведений по умолчанию (т.е. переопределить некоторые методы) или хотите получить доступ к некоторым защищенным полям класса Thread. Если вы не хотите этого, вы выбираете более слабую связь - реализует Runnable и передает его в качестве параметра конструктора в экземпляр Thread.