写了下Swing方面的代码:
对Swing线程方面的知识不是很理解。import java.awt.Button;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;public class JFrameGo extends JFrame
{
private static final long serialVersionUID = 1L;
private TextField text = new TextField(10);
private Button start = new Button("Start");
private Button end = new Button("End");
private boolean flag = true;
JFrameGo()
{
Container containPane = this.getContentPane();
        containPane.setLayout(new FlowLayout());
containPane.add(text);
containPane.add(start);
containPane.add(end);
start.addActionListener(new Start());
end.addActionListener(new End());
}

public void go()
{
int count = 0;
while(true && count < 50)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(flag)
{
count++;
text.setText(String.valueOf(count));
}
}
}

private class Start implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
go();
}
}

private class End implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
flag = false;
}
}
public static void main(String[] args)
{
JFrameGo fg = new JFrameGo();
        fg.setSize(300, 200);
        fg.setVisible(true);
}
}
在上面的代码打开的窗口中,按下“Start”按钮,待循环完成之前(go()方法),“End”按钮不可以按的。
资料说的是:是把“Start”和“End”的线程放进分派线程中的。只有当一个结束时,另一个才可以执行。
这好像和两个平常(非触发事件)单独的线程执行起来的效果不一样。(因为:一个线程的变量状态可以被另一个线程改变,并不需要前一个线程先执行完)。
也就是说:按钮事件的触发的两个线程 和 两个平常(非触发事件)单独的线程 执行起来的效果不一样。
不知道理解的对不对?

解决方案 »

  1.   

    答:
    1)当你按下:start按钮时,要进行go()的计算,这个计算是由"事件分发线程"(即:专门管理键盘,mouse,GUI界面响应处理的线程)进行的,这样:当这个线程忙于go()的计算,就再没有时间去响应键盘,mouse,GUI界面响应处理了,即你说的:待循环完成之前(go()方法),“End”按钮不可以按的。 
    2)因此:SWING的GUI设计要求:计算耗时的操作,不能用:"事件分发线程"去做,应另外设计一个线程("工作线程"),专门去进行计算.这样,:"事件分发线程"专门负责管理键盘,mouse,GUI界面响应处理
    3)由于SWING是线程不安全的,因此:所有的GUI界面更新都必须由:"事件分发线程"去做,不能由:上边的"工作线程"去做.
    即:不能从"工作线程"中直接更新GUI组件(只能少量GUI组件可以),应该用:SwingUtilities.invokeLater(Runnable doRun)或SwingUtilities.invokeAndWait(Runnable doRun)来请求事件分发线程去帮它更新GUI组件
      

  2.   

    首先,谢谢二楼的回答。
    1 ------SWING的GUI设计要求:计算耗时的操作,不能用:"事件分发线程"去做,应另外设计一个线程("工作线程").
    也就是说,我的go()方法不能放在分发线程中,即:go()方法不能加到SwingUtilities.invokeLater(Runnable doRun)块里去了,
    而要放到一个单独的线程里。
    2 ------由于SWING是线程不安全的,因此:所有的GUI界面更新都必须由:"事件分发线程"去做,不能由:上边的"工作线程"去做.
    因为”text.setText(String.valueOf(count));“放在go()的代码块中,也就是说text.setText(String.valueOf(count))要改放在
    SwingUtilities.invokeLater(Runnable doRun)代码块中了。
    综合1,2的话,go()方法和”text.setText(String.valueOf(count));“要分开写了?
    不知道,代码改做如何修改呢,希望不吝赐教啊。
      

  3.   

    为什么swing是线程不安全的,怎么判断某某某是不是线程安全捏
      

  4.   

    答:
    1)go()必需放在另一个线程中(即:工作线程来做)
    2)text.setText(String t);虽然大多数 Swing 方法不是线程安全的,但此方法是线程安全的。因而可在"工作线程"中直接调用.
      

  5.   

    答:关于swing与线程的问题及程序设计,见http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
      

  6.   

    谢谢楼上的。
    我把代码修改了下:import java.awt.Button;
    import java.awt.FlowLayout;
    import java.awt.Frame;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;public class FrameGo extends Frame implements Runnable
    {
    private static final long serialVersionUID = 1L;
    private TextField text = new TextField(10);
    private Button start = new Button("Start");
    private Button end = new Button("End");
    private boolean flag = false;
    FrameGo()
    {
    this.setLayout(new FlowLayout());
    add(text);
    add(start);
    add(end);
    start.addActionListener(new Start());
    end.addActionListener(new End());
    }

    public void run()
    {
    int count = 0;
    while(true && count < 50)
    {
    try
    {
    Thread.sleep(100);
    }
    catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    if(flag)
    {
    count++;
    text.setText(String.valueOf(count));
    }
    }
    }

    private class Start implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
    {
    flag = true;
    }
    }

    private class End implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
    {
    flag = false;
    }
    }
    public static void main(String[] args)
    {
    FrameGo fg = new FrameGo();
    Thread th = new Thread(fg);
    th.start();
            fg.setSize(300, 200);
            fg.setVisible(true);
    }
    }现在是把之前的go()里做的事情,放在线程的run()方法里来做了。
    因为:text.setText(String t);虽然大多数 Swing 方法不是线程安全的,但此方法是线程安全的。因而可在"工作线程"中直接调用.
    我想问的是:如果此处(也就是run())方法里,如果有线程不安全的方法的话,该如何处理呢?
    因为此处run()是一个计算耗时的操作,所以应该不能放入SwingUtilities.invokeLater(Runnable doRun)块里去了吧?
      

  7.   

    我想问的是:如果此处(也就是run())方法里,如果有线程不安全的方法的话,该如何处理呢? 
    因为此处run()是一个计算耗时的操作,所以应该不能放入SwingUtilities.invokeLater(Runnable doRun)块里去了吧?
    答:
    设语句:myGUI.setGUIText(...)是更新GUI界面的动作,而且是线程不安全的.如何从当前的工作线程中,请求"事件分发线程"来执行:myGUI.setGUIText(...)?
    代码如下:
    SwingUtilities.invokeLater(
     new Runnable() {
        public void run() { myGUI.setGUIText(...); }
    } );
      

  8.   

    谢谢楼上的回答。
    在我之前的代码中,text.setText(String.valueOf(count));
    已经放在run()方法中做了循环,判断处理。
    如果现在把myGUI.setGUIText(...); 放入一个新的线程中的话,
    也就是说:
    SwingUtilities.invokeLater( 
    new Runnable() { 
        public void run() { myGUI.setGUIText(...); } 
    } ); 
    那我在何处开始此线程的start()方法?
      

  9.   

    来晚了。
    我写个试试:import java.awt.Button;
    import java.awt.FlowLayout;
    import java.awt.Frame;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;import javax.swing.SwingUtilities;public class FrameGo extends Frame implements Runnable {
    private static final long serialVersionUID = 1L; private TextField text = new TextField(10); private Button start = new Button("Start"); private Button end = new Button("End"); private boolean flag = false;

    private int count = 0;//定义成员变量,保存在工作线程中被更改的值

    private Runnable runSimple = null;//要在事件派发线程队列中排队的UI更新线程 FrameGo() {
    this.setLayout(new FlowLayout());
    add(text);
    add(start);
    add(end);
    start.addActionListener(new Start());
    end.addActionListener(new End());
                    //初始化UI更新线程
    runSimple = new Runnable() {
    public void run() {
    text.setText(String.valueOf(count));//更新UI
    }
    };
    } public void run() {
    count = 0;
    while (true && count < 50) {
    try {
    Thread.sleep(100);//耗时的工作
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    if (flag) {
    count++;
    SwingUtilities.invokeLater(runSimple);//将UI更新线程放到事件派发线程中,排队
    }
    }
    } private class Start implements ActionListener {
    public void actionPerformed(ActionEvent e) {
    flag = true;
    }
    } private class End implements ActionListener {
    public void actionPerformed(ActionEvent e) {
    flag = false;
    }
    } public static void main(String[] args) {
    FrameGo fg = new FrameGo();
    Thread th = new Thread(fg);
    th.start();
    fg.setSize(300, 200);
    fg.setVisible(true);
    }
    }
      

  10.   

    答:
    1)对于你的text.setText(....),由于是线程安全的,故这个技术(SwingUtilities.invokeLater(..))不需要.
    2)若myGUI.setGUIText(...); 不是SWING线程安全的,则:你只要用:SwingUtilities.invokeLater(..)向"事件分发线程"发出GUI更新请求就行了.不需要你来调用这个start()的.事件分发线程 会自己处理的.你只管负责你的工作线程就行了.