Не уверен, что вы используете правильный механизм синхронизации здесь.
Ваш поток выглядит следующим образом
- Поток 1 захватывает монитор
- Поток 1 проверяет состояние сервера
- Сервер не готов
- Поток 1 отбрасывает монитор и ожидает
- Поток 2 захватывает монитор
- Поток 2 проверяет состояние сервера
- Сервер не готов
- Поток 2 отбрасывает монитор и ждет
- Тупик, поскольку оба потока ожидают друг друга
Поэтому потоки не могут пройти проверку сервера, поскольку никто уведомит, что они могут продолжить. Чтобы это было возможно, вам нужен либо поток 1, либо поток 2, чтобы уведомить другой, когда оба будут готовы, что приведет к тупику.
Возможно, вы захотите рассмотреть, например, использование Cycli c Барьер вместо. Это позволит вам подождать, пока вы не наберете достаточно потоков, чтобы начать игру.
private static Object lock = new Object();
private static CyclicBarrier barrier = new CyclicBarrier(2, () -> setReady());
...
@Override
public void run() {
System.out.println(String.format(" --> Server handler: %s is in run method...", serverID));
while (true) {
synchronized (lock){
while (!Server.isFinished()) {
try {
System.out.println(String.format(" --> Server handler: %s is waiting...", serverID));
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println(String.format(" --> Server handler: %s is ready to send board...", serverID));
sendBoard();
notify();
}
}
}
public static void setReady() {
synchronized (lock) {
try {
sendBoard();
System.out.println(String.format(" --> Server handler: %s is waiting...", serverID));
lock.notify();
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
Нечто подобное позволит изменить блок до тех пор, пока оба потока не запустятся, второй поток не достигнет барьера, а затем не вызовет метод setReady, отправляющий доску перед ожиданием в другом потоке.