Многопоточное исключение IllegalMonitorStateException

Я пишу многопоточную программу крестики-нолики, в которой сервер - это соединение между двумя клиентами. Сервер открывается и ожидает подключения: первый клиент для подключения - это игрок X, а второй - игрок O. Игроки имеют возможность выйти из игры в любой момент, и как только клиент выходит из игры, другой клиент сбрасывает свою доску и ждет новое соединение. Эта часть работает нормально, но проблема в том, что как только я создаю нового клиента, я получаю следующие ошибки:

Exception in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException at java.base/java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:149) at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1300) at java.base/java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:439) at TicTacToeServer.processMessage(TicTacToeServer.java:329) at TicTacToeServer$Player.run(TicTacToeServer.java:498) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:844)

Похоже, что именно тот поток, который был закрыт, вызывает эту ошибку. Игрок X всегда является тем клиентом, который подключается первым, поэтому это всегда поток 1, в то время как игрок O всегда поток 2. Из-за указанной выше ошибки я закрыл игрока X и открыл новый (поток 3).

В каждом клиентском окне есть кнопка, позволяющая им выйти, которая использует прослушиватель действий, созданный, как показано:

quitGame = new JButton("Quit");
  quitGame.addActionListener(new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           System.out.println("Quit button was clicked!");
           displayMessage( "You have quit the game.\n" );
           output.format("Quit. " + myMark + "\n");
           output.flush();
           try
           {
               connection.close(); // close connection to client
               System.exit(0);
           } // end try
           catch ( IOException ioException )
           {
               ioException.printStackTrace();
               System.exit( 1 );
           } // end catch
       }
   });
  panel2.add( quitGame, BorderLayout.SOUTH ); // add button to panel
  add( panel2, BorderLayout.CENTER ); // add container panel

Это соответствует следующему коду на сервере:

else if (message.equals("Quit. X")) {
        //connection.close(player[PLAYER_X]);
        currentPlayer = PLAYER_X;
        displayMessage("\nPlayer X has ended the game.\n");
        players[1].send("Player X has ended the game.");
        players[1].send("Please wait for new player to connect.");

        players[(currentPlayer+1)%2].send("Restart.");
        players[currentPlayer].send("Restart.");
        for(int x = 0;x<board.length;x++)
        {
            board[x] = "";
            numRep[x] = 4;
        }// end for loop

        try // wait for connection, create Player, start runnable
        {
            players[ 0 ] = new Player( server.accept(), 0 );
            Player temp = players[0];
            players[1].send("New player has connected. Game on!");
            players[1].send("Please wait for your turn.");
            runGame.execute( players[0] ); // execute player runnable
        } // end try
        catch ( IOException ioException )
        {
            ioException.printStackTrace();
            System.exit( 1 );
        } // end catch

        //gameLock.lock();
        try // allow x to go first
        {
            players[ PLAYER_X ].setSuspended( false ); // resume player X
            otherPlayerConnected.signal(); // wake up player X's thread
        } // end try
        finally
        {
            gameLock.unlock(); // unlock game after signaling player X
        } // end finally
    } // end if

В сообщении об ошибке упоминаются следующие строки:

    gameLock.unlock(); // unlock game after signaling player X

который показан в блоке finally выше и

if ( input.hasNextLine() )
        processMessage(input.nextLine()); // get message

Это находится в run () и вызывает processMessage, который обрабатывает сообщения, отправленные клиентом, и частично показан выше.

Я пытался возиться с закрытием соединения, ввода, вывода и т. д., Но я не могу избавиться от этой ошибки. Я предполагаю, что это не влияет на саму игру, потому что ошибка связана с закрытым потоком, но я все же хотел бы ее исправить. Любая помощь приветствуется!

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
620
1

Ответы 1

Из докReentrantLock.unlock():

If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

Вам необходимо приобрести замок до unlock.

Новый тред / плеер или тот, который закрыт? Также как мне получить блокировку? Я думал, это просто для игры

meowyadoin 06.05.2018 18:24

Другие вопросы по теме