2013-06-12 59 views
6

我真的很困惑:我的一些代碼不能正常工作,當我在eclipse中正常運行我的程序,但是當我運行時分步使用調試模式。代碼在正常運行時不工作,但在調試(日食)中工作

代碼:

public void showConnectDialog() { 
    ConnectDialog connectDialog = new ConnectDialog(); 
    connectDialog.setVisible(true); 
    //Until here, code runs 
    while(! connectDialog.getConnected()) {}; 
    //The next line does only run in debug 
    JOptionPane.showMessageDialog(connectDialog, "Connected", "Connected", JOptionPane.INFORMATION_MESSAGE); 

} 

(在對話框中開始(如線程),一旦用戶點擊 '連接')的連接器:

private class ServerConnector implements ActionListener, Runnable { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (! IP_field.getText().equals("")) { 
      if (! isConnecting) { 
       new Thread(new ServerConnector(), "ServerConnector").start(); 

      } 

     } 
     else { 
      JOptionPane.showMessageDialog(dialog, 
              "Enter an IP address", 
              "Enter IP", 
              JOptionPane.WARNING_MESSAGE); 

     } 

    } 

    @Override 
    public void run() { 
     try { 
      setConnecting(true); 
      Socket socket = connect(); 
      if (socket != null) { 
       ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream()); 
       ObjectInputStream oIn = new ObjectInputStream(socket.getInputStream()); 
       if (login(oOut, oIn)) { 
        isConnected = true; 
        setConnecting(false); 

       } 
       else { 
        socket.close(); 

       } 

       setConnecting(false); 

      } 

     } 
     catch (RSPException e) { 
      e.printStackTrace(); 
      System.exit(1); 

     } 
     catch (Exception e) { 
      //If an exception occurs, setConnecting() will be true. This 
      //not good, so it has to be set to false 
      e.printStackTrace(); 
      setConnecting(false); 

     } 

    } 

    private boolean login(ObjectOutputStream oOut, ObjectInputStream oIn) 
      throws ClassNotFoundException, IOException, RSPException { 
     //Send login request action: 
     oOut.writeObject(new LoginAction(ActionSender.CLIENT, getID(), 
             getPassword())); 

     Object obj = oIn.readObject(); 
     if (obj instanceof LoginActionResult) { 
      LoginActionResult result = (LoginActionResult) obj; 
      if (result.getResult() == LoginResults.SUCCES) { 
       return true; 

      } 
      else if (result.getResult() == LoginResults.FAIL_ON_ID) { 
       JOptionPane.showMessageDialog(dialog, 
               "Invalid password or ID", 
               "Can't login", 
               JOptionPane.ERROR_MESSAGE); 
       return false; 

      } 
      else if (result.getResult() == LoginResults.FAIL_ON_PASSWORD) { 
       JOptionPane.showMessageDialog(dialog, 
               "Invalid password or ID", 
               "Can't login", 
               JOptionPane.ERROR_MESSAGE); 
       return false; 

      } 
      else if (result.getResult() == LoginResults.SERVER_FULL) { 
       JOptionPane.showMessageDialog(dialog, 
               "Couldn't connect: \n" + 
               "Server is full", 
               "Failed to connect", 
               JOptionPane.WARNING_MESSAGE); 
       return false; 

      } 
      else { 
       return false; 

      } 

     } 
     else { 
      System.out.println(obj); 
      throw new RSPException("Server is not following the protocol."); 

     } 

    } 

    private void setConnecting(boolean connecting) { 
     if (connecting) { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setEnabled(false); 

       } 
      }); 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setText("Connecting..."); 

       } 
      }); 

     } 
     else { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setText("Connect"); 

       } 
      }); 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        connectButton.setEnabled(true); 

       } 
      }); 

     } 

     isConnecting = connecting; 

    } 

    private String getAddressFromTextField() { 
     return IP_field.getText(); 

    } 

    private InetAddress getInetAddress(String fullAddress) { 
     try { 
      if (fullAddress.contains(":")) { 
       String[] splitAddress = fullAddress.split(":"); 
       return InetAddress.getByName(splitAddress[0]); 

      } 
      else { 
       return InetAddress.getByName(fullAddress); 

      } 
     } 
     catch (UnknownHostException e) { 
      return null; 

     } 

    } 

    private int getPort(String fullAddress) { 
     try { 
      String[] splittedAddress = fullAddress.split(":"); 
      return Integer.valueOf(splittedAddress[1]); 

     } 
     catch (NumberFormatException ex) { 
      return -1; 

     } 
     catch (NullPointerException 
      | ArrayIndexOutOfBoundsException 
      | PatternSyntaxException ex) { 
      //Returning default port value: 25566, because no port was given 
      return 25566; 

     } 

    } 

    @SuppressWarnings("resource") 
    private Socket connect() { 
     Socket socket = null; 

     InetAddress address = null; 
     if ((address = getInetAddress(getAddressFromTextField())) == null) { 
      return null; 

     } 
     int port = getPort(getAddressFromTextField()); 

     try { 
      socket = new Socket(address, port); 

     } 
     catch (ConnectException e) { 
      Socket retrySocket = null; 
      if ((retrySocket = retryConnect(address, port)) == null) { 
       JOptionPane.showMessageDialog(dialog, 
               "Connection timed out", 
               "Failed to connect", 
               JOptionPane.ERROR_MESSAGE); 
       setConnecting(false); 

      } 
      else { 
       socket = retrySocket; 

      } 

     } 
     catch(IOException e) { 
      e.printStackTrace(); 

     } 

     return socket; 

    } 

    private Socket retryConnect(InetAddress address, int port) { 
     Thread waitThread = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        //Will wait 15(000) (milli)seconds before stopping with 
        //trying to connect. 
        //One second (1000 millis) is for debugging and testing 
        Thread.sleep(1000); 

       } 
       catch (InterruptedException e) { 
        e.printStackTrace(); 

       } 

      } 

     }); 

     waitThread.start(); 

     while (waitThread.isAlive()) { 
      try { 
       return new Socket(address, port); 

      } 
      catch (ConnectException e) { 
       //Do nothing, will re-attempt to connect. 

      } 
      catch (IOException e) { 
       e.printStackTrace(); 

      } 

     } 

     return null; 

    } 

    private String getID() { 
     return ID_field.getText(); 

    } 

    private String getPassword() { 
     if (getID().equals("master")) { 
      return "masterPassword"; 

     } 
     else { 
      return new String(passwordField.getPassword()); 

     } 

    } 

} 

getConnected()回報true儘快它連接到服務器。連接器在單獨的線程上運行。

編輯:我試圖把代碼放在getConnected(),而塊,然後它的工作。爲什麼它會起作用,而不是其他?

+3

可能是一種競爭條件。你可以將代碼發佈到'ConnectDialog'嗎? – austin

+0

你在休息時間評估任何表情嗎?這些評估實際上可以改變你的程序的狀態(也許你很幸運,它將它改變成工作狀態?) –

+0

@austin ConnectDialog代碼長700行,所以我只會將代碼發佈到實際的連接器(它仍然很長...)希望你的罰款。 – Creator13

回答

3

我有同樣的問題,但有一些更多的規範。該代碼在32位工作正常,但我有這個問題在64位(我使用本機庫,所以我需要維護兩者)。

我發現的解決方案是在while循環中添加Thread.sleep()。我不知道它爲什麼起作用,所以你的猜測和我的一樣好。

更好的解決方案可能會實現Observer Pattern而不是無限循環。但是這需要一些重新考慮因素。

2

我有一個非常類似的問題與「while」循環不會運行,該循環是我的主要例程。我如何得到了循環運行的是,這是在循環中完成的第一件事是睡眠:

try 
     {Thread.sleep(0);} 
    catch (Exception e) 
     {e.printStackTrace();} 

這是足以讓一切順利。

0

使用Thread.sleep(),正如其他答案所建議的,應該解決問題,但它不是一個很好的方法。相反,我們應該使用Thread.yield()

爲什麼yield而不是sleep

參見: Difference between Thread.Sleep(0) and Thread.Yield()Are Thread.sleep(0) and Thread.yield() statements equivalent?

爲什麼這個工程?

當我們剛剛運行線程時,操作系統將它們置於「空閒」狀態,並且當它預計「喚醒」時,它不會。另一方面,在調試模式下,我們有一個受控制的環境。操作系統幾乎無法控制它,因爲一切都在緩慢地逐步進行。如果我們幾次運行調試而沒有任何中斷點,在幾次成功運行後,我們應該看到相同的效果。

相關問題