问下为什么要加EventQueue.invokeLater

时间:2022-05-06 03:03:20
Core Java中每当创建一个窗口的时候都会在外面写这么一个东西,比如:

import java.awt.*;
import javax.swing.*;

public class Test 
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setSize(400, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
}

书上貌似也没有说为什么,只是说这样写会更安全,我不是很明白它的意思,谁能具体讲讲为什么?不加EventQueue.invokeLater行吗?

6 个解决方案

#2


引用 1 楼 lingyue1012 的回复:
http://zhidao.baidu.com/question/161013053.html?push=ql

为什么我感觉加不加效果一样呢?
参考下面的一段代码,随便连接一个无法连接到的主机,在程序发出连接超时错误之前,整个程序都是死掉的,因此可以看出,即使加了EventQueue.invokeLater之后,这个程序依旧是单线程的,不相信大家对着下面的程序试试。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

@SuppressWarnings("serial")
public class Talk extends JFrame
{
private ServerSocket server;
private Socket[] sockets;
private static final int MAX_LINK = 10;

public Talk() throws IOException 
{
server = new ServerSocket(1680);
sockets = new Socket[MAX_LINK];
new ListenThread().start();

JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
JMenuItem newItem = new JMenuItem("New Connection");
JMenuItem exitItem = new JMenuItem("Exit");
menu.add(newItem);
menu.addSeparator();
menu.add(exitItem);

setJMenuBar(menuBar);

newItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
final String ip = JOptionPane.showInputDialog(Talk.this, "Please input a IP address: ");
if (ip == null || ip.equals(""))
return;

/*
 * 就是下面的这段代码,虽然看上去像多线程,但事实上整个程序依旧是单线程的,为什么会这样呢?
 */
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, 1680), 10000);
JFrame frame = new TalkFrame(socket);
frame.setVisible(true);
}
catch (SocketTimeoutException e)
{
JOptionPane.showMessageDialog(Talk.this, "connect timeout");
}
catch (IOException e)
{
e.printStackTrace();
}

}
});
}
});
exitItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.exit(0);
}
});
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
JFrame frame = new Talk();
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}

private class ListenThread extends Thread
{
public void run()
{
while (true)
{
for (int i = 0; i < MAX_LINK; i++)
{
try
{
sockets[i] = server.accept();
JFrame frame = new TalkFrame(sockets[i]);
frame.setVisible(true);

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

private class TalkFrame extends JFrame
{
private JTextArea record = new JTextArea(10, 30);
private JTextField message = new JTextField(20);
private JButton button = new JButton("Send");
private PipedWriter pipeOut;
private PipedReader pipeIn;

public TalkFrame(Socket socket) throws IOException
{
pipeOut = new PipedWriter();
pipeIn = new PipedReader(pipeOut);
String ip = socket.getInetAddress().getHostAddress();
setTitle("Talk with " + ip);
setLayout(new BorderLayout());

add(new JLabel("Talk Record: "), BorderLayout.NORTH);
add(new JScrollPane(record), BorderLayout.CENTER);
record.setEditable(false);

JPanel panel = new JPanel();
panel.add(new JLabel("Message: "));
panel.add(message);
panel.add(button);
add(panel, BorderLayout.SOUTH);

button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
PrintWriter out = new PrintWriter(pipeOut);
out.println(message.getText());
record.append("I: " + message.getText() + "\n");
message.setText("");
}
});
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
setVisible(false);
record.setText("");
}
});
new WriteThread(pipeIn, new PrintWriter(socket.getOutputStream())).start();
new ReadThread(this, ip, record, new BufferedReader(new InputStreamReader(socket.getInputStream()))).start();
setSize(400, 300);
setLocationByPlatform(true);
setVisible(true);
}
}

private class WriteThread extends Thread
{
private PrintWriter out;
private BufferedReader in;

public WriteThread(PipedReader pipeIn, PrintWriter out)
{
this.out = out;
this.in = new BufferedReader(pipeIn);
}

public void run()
{
while (true)
{
try
{
while (true)
{
String s = in.readLine();
out.println(s);
out.flush();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}

private class ReadThread extends Thread
{
private BufferedReader in;
private JTextArea record;
private String ip;
private JFrame frame;

public ReadThread(JFrame frame, String ip, JTextArea record, BufferedReader in)
{
this.frame = frame;
this.ip = ip;
this.in = in;
this.record = record;
}

public void run()
{
while (true)
{
try
{
record.append(ip + ": " + in.readLine() + "\n");
frame.setVisible(true);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}

#3


我也遇到这个问题

#4


我今天也遇见了这个问题,从网上找了一下答案。其中有一个答案是这样的:
Java's GUI is strictly single-threaded.
All GUI related things in java should always go through a single thread. The thread is our legendary "AWT-EventQueue-0"   . Hence all GUI related actions should necessarily go through the AWT Event thread. If not so you may end up in a deadlock. For small programs, this might never happen. But for a huge java application if you try frame.setVisible(true) kind of thing in main thread, you will soon find yourself searching a new job. What invokeLater() does is to post your Runnable in the AWT thread's event queue. So the code in your run method will be executed in the AWT-Eventqueue thread.
大意是说,java的GUI都是的单线程,应该使用事件调度线程去执行,如果没意思使用事件调度线程的话,可能造成死锁。但是在小的程序中,这种现象(死锁)不会发生的;大的应用程序中才会出现这种现象!

#5


没看懂。

#6


我要看~

#1


#2


引用 1 楼 lingyue1012 的回复:
http://zhidao.baidu.com/question/161013053.html?push=ql

为什么我感觉加不加效果一样呢?
参考下面的一段代码,随便连接一个无法连接到的主机,在程序发出连接超时错误之前,整个程序都是死掉的,因此可以看出,即使加了EventQueue.invokeLater之后,这个程序依旧是单线程的,不相信大家对着下面的程序试试。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

@SuppressWarnings("serial")
public class Talk extends JFrame
{
private ServerSocket server;
private Socket[] sockets;
private static final int MAX_LINK = 10;

public Talk() throws IOException 
{
server = new ServerSocket(1680);
sockets = new Socket[MAX_LINK];
new ListenThread().start();

JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
JMenuItem newItem = new JMenuItem("New Connection");
JMenuItem exitItem = new JMenuItem("Exit");
menu.add(newItem);
menu.addSeparator();
menu.add(exitItem);

setJMenuBar(menuBar);

newItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
final String ip = JOptionPane.showInputDialog(Talk.this, "Please input a IP address: ");
if (ip == null || ip.equals(""))
return;

/*
 * 就是下面的这段代码,虽然看上去像多线程,但事实上整个程序依旧是单线程的,为什么会这样呢?
 */
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, 1680), 10000);
JFrame frame = new TalkFrame(socket);
frame.setVisible(true);
}
catch (SocketTimeoutException e)
{
JOptionPane.showMessageDialog(Talk.this, "connect timeout");
}
catch (IOException e)
{
e.printStackTrace();
}

}
});
}
});
exitItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.exit(0);
}
});
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
JFrame frame = new Talk();
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}

private class ListenThread extends Thread
{
public void run()
{
while (true)
{
for (int i = 0; i < MAX_LINK; i++)
{
try
{
sockets[i] = server.accept();
JFrame frame = new TalkFrame(sockets[i]);
frame.setVisible(true);

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

private class TalkFrame extends JFrame
{
private JTextArea record = new JTextArea(10, 30);
private JTextField message = new JTextField(20);
private JButton button = new JButton("Send");
private PipedWriter pipeOut;
private PipedReader pipeIn;

public TalkFrame(Socket socket) throws IOException
{
pipeOut = new PipedWriter();
pipeIn = new PipedReader(pipeOut);
String ip = socket.getInetAddress().getHostAddress();
setTitle("Talk with " + ip);
setLayout(new BorderLayout());

add(new JLabel("Talk Record: "), BorderLayout.NORTH);
add(new JScrollPane(record), BorderLayout.CENTER);
record.setEditable(false);

JPanel panel = new JPanel();
panel.add(new JLabel("Message: "));
panel.add(message);
panel.add(button);
add(panel, BorderLayout.SOUTH);

button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
PrintWriter out = new PrintWriter(pipeOut);
out.println(message.getText());
record.append("I: " + message.getText() + "\n");
message.setText("");
}
});
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
setVisible(false);
record.setText("");
}
});
new WriteThread(pipeIn, new PrintWriter(socket.getOutputStream())).start();
new ReadThread(this, ip, record, new BufferedReader(new InputStreamReader(socket.getInputStream()))).start();
setSize(400, 300);
setLocationByPlatform(true);
setVisible(true);
}
}

private class WriteThread extends Thread
{
private PrintWriter out;
private BufferedReader in;

public WriteThread(PipedReader pipeIn, PrintWriter out)
{
this.out = out;
this.in = new BufferedReader(pipeIn);
}

public void run()
{
while (true)
{
try
{
while (true)
{
String s = in.readLine();
out.println(s);
out.flush();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}

private class ReadThread extends Thread
{
private BufferedReader in;
private JTextArea record;
private String ip;
private JFrame frame;

public ReadThread(JFrame frame, String ip, JTextArea record, BufferedReader in)
{
this.frame = frame;
this.ip = ip;
this.in = in;
this.record = record;
}

public void run()
{
while (true)
{
try
{
record.append(ip + ": " + in.readLine() + "\n");
frame.setVisible(true);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}

#3


我也遇到这个问题

#4


我今天也遇见了这个问题,从网上找了一下答案。其中有一个答案是这样的:
Java's GUI is strictly single-threaded.
All GUI related things in java should always go through a single thread. The thread is our legendary "AWT-EventQueue-0"   . Hence all GUI related actions should necessarily go through the AWT Event thread. If not so you may end up in a deadlock. For small programs, this might never happen. But for a huge java application if you try frame.setVisible(true) kind of thing in main thread, you will soon find yourself searching a new job. What invokeLater() does is to post your Runnable in the AWT thread's event queue. So the code in your run method will be executed in the AWT-Eventqueue thread.
大意是说,java的GUI都是的单线程,应该使用事件调度线程去执行,如果没意思使用事件调度线程的话,可能造成死锁。但是在小的程序中,这种现象(死锁)不会发生的;大的应用程序中才会出现这种现象!

#5


没看懂。

#6


我要看~