java无限循环奇怪行为

时间:2015-10-31 11:21:25

标签: java swing while-loop stream client-server

我有这个简单的网络代码(我正在尝试实现一个简单的聊天服务器作为练习),但我陷入困境,我无法弄清楚发生了什么。 我为我的客户端创建了GUI,它有一个另一个类的实例,它执行连接和发送/接收消息到我的服务器的所有必要操作。

package com.luca.chat;

import java.awt.*
import java.awt.event.*
import javax.swing.*

class Window extends JFrame {

  private final static int WIDTH=500;
  private final static int HEIGHT=300;

  private String status="disconnected";

  private JPanel panel;
  private JTextArea area;
  private JTextField field,address;
  private JButton button;
  private JLabel label;

  private IOClass io=new IOClass(this);

  Window() {
    super("Chit-Chat");
    setSize(new Dimension(WIDTH,HEIGHT));
    ImageIcon icon=new ImageIcon("..\\images\\lucas.png");
    setIconImage(icon.getImage());

    JPanel contentPane=(JPanel)getContentPane();

    // add the text area to display incoming and outgoing messages
    area=new JTextArea();
    area.setEditable(false);
    contentPane.add(area,BorderLayout.CENTER);

    // add text field to send messages
    field=new JTextField(20);
    field.addActionListener(new ActionListener(){ 
      public void actionPerformed(ActionEvent e) {
        String message=field.getText();
        io.send(message);
        field.setText("");
      }
    });
    panel=new JPanel();
    panel.add(field);
    panel.setBorder(BorderFactory.createEtchedBorder());
    contentPane.add(panel,BorderLayout.SOUTH);

    // add status bar on top 
    label=new JLabel("status: "+status);  
    address=new JTextField(15);
    button=new JButton("connect");
    panel=new JPanel();  
    panel.add(label);
    panel.add(address);
    panel.add(button);  
    button.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e) {
        io.connect(address.getText());
      }
    }); 
    panel.setBorder(BorderFactory.createEtchedBorder());
    contentPane.add(panel,BorderLayout.NORTH);

    Toolkit kit=getToolkit();
    Dimension dim=kit.getScreenSize();
    setLocation((dim.width-WIDTH)/2,(dim.height-HEIGHT)/2);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);

    loop();
  }

  void loop() { 
    while (true) 
      if (io.connected) 
        io.receive(); 
      else            // if I comment this line out it never calls receive() ?????    
        System.out.println("????"); 
  }

  void setStatus(String status) {
    label.setText(status);
  }

  void setText(String received) {
    area.append(received);
  }

  public static void main(String[] args) {
    new Window();
  }


}

IOClass有连接/发送/接收的所有方法(我认为它的作用类似于控制器?我不知道,我只是开始学习这种模式)一个标志,它控制是否连接是否建立。 如果有连接,它会调用receive方法,这是一个无限循环来监听传入的消息。

但是如果我只留下if语句(内部循环())没有别的......它就不会执行!我的意思是.. while循环永远不会开始(我尝试了一些打印件......它永远不会到达那里)但是如果我添加了其他的话它会到达那里!

例如,

阻塞if语句:

 void loop() { 
   while (true) 
     if (io.connected) 
       io.receive(); 
 }

这是有效的(while循环永远):

 void loop() { 
   while (true) 
     if (io.connected) 
       io.receive();   
     else
        ....do something else...
 }

甚至可行:

 void loop() {
   while (true) { 
     System.out.println("whatever"); 
     if (io.connected) 
       io.receive();
   }  // end of while
 }

我无法理解,这对我来说似乎是一种非常奇怪的行为。

编辑:使用Eclipse的调试功能我看到,当它工作时,while循环会按预期永久循环,当它不存在时,它只是在if条件下阻塞

2 个答案:

答案 0 :(得分:0)

void loop() { 
    while (true) 
      if (io.connected) 
        io.receive(); 
      else  // if I comment this line out it never calls receive() ?????    
        System.out.println("????"); 
}

在你的答案的例子中,你指出这个代码是罪魁祸首。由于while没有括号{},因此只有下一行才会被视为while循环的主体。 if没有括号也是如此:只有真实条件中的第一行才会执行。它可能会或可能不会跟随else - 条款。

在您的情况下,由于while之后的下一行是if-else且两个条件只有一行要执行,因此您的while循环按预期工作。

如果您的意思是:

void loop() { 
    while (true) 
      if (io.connected) 
        io.receive(); 
      //else   
        System.out.println("????"); 
}

然后这不会编译,因为你告诉System.out.println("????");执行 AFTER while循环完成并且while循环的条件显式为true;永远不会达到代码。如果您使用变量作为标志,它将进行编译,当循环完成时,您将体验System.out.println("????");将执行一次。

答案 1 :(得分:0)

在Eclipse调试器的帮助下,一步一步地,我找到了捕获。 因为当我实例化JFrame时,JVM会自动旋转一个新线程(Event队列),因为它是使用连接按钮注册的ActionListener,它调用将boolean标志设置为true的connect()方法,标志为true在这一个线程中,但是在主线程中它仍然是假的,所以if条件永远不会计算为true,因此,我挂起等待调用receive()方法,并且我在屏幕上没有输出。 使用volatile修饰符可以解决问题,因此更新的变量对所有线程都是自动可见的。 由于我是新手,所以这并不是那么明显......但是评论让我朝着正确的方向前进。