Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 回转中的螺纹和JLabel-工作不正常_Java_Multithreading_Swing_Jbutton_Jlabel - Fatal编程技术网

Java 回转中的螺纹和JLabel-工作不正常

Java 回转中的螺纹和JLabel-工作不正常,java,multithreading,swing,jbutton,jlabel,Java,Multithreading,Swing,Jbutton,Jlabel,请看下面的代码 import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JFrame; import javax.swing.JPanel; class thread_jishu extends Thread{ @Override public void run(){ int p=-1; for(;;){ //here contin

请看下面的代码

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;

class thread_jishu extends Thread{
    @Override
    public void run(){
        int p=-1;
        for(;;){
            //here continuously checking that whether
            //the value of label_thread.i is equals to p or not

            if(label_thread.i!=p){
                try{
                    Thread.sleep(1000);
                }catch(Exception e){}

                label_thread.lb.setText("after sleeping at -> "+label_thread.i);
                // here i want to set the JLabel
                // text after waiting 1sec only when
                // label_thread.i has been changed,
                // but not happening 
                p=label_thread.i;
            }
        }
    }
}

public class label_thread  implements java.awt.event.ActionListener{

    /**
     * @param evt
     */
    @Override
    public void actionPerformed(java.awt.event.ActionEvent evt){
        i+=1;
        lb.setText("Button clicked at -> "+i);
    }

    static int i=-1;
    static JLabel lb=new JLabel("hello here");
    static JFrame window=new JFrame("Jishu");
    static JFrame window2=new JFrame("Jishu");

    public static void main(String[] args) {
        // TODO code application logic here
        new thread_jishu().start();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setMinimumSize(new java.awt.Dimension(200,200));

        JButton bt=new JButton("Click here");
        bt.addActionListener(new label_thread());
        JPanel panel=new JPanel();
        panel.add(bt);
        window.add(panel);
        window2.add(lb);
        window.setVisible(true);
        window2.setVisible(true);
        window2.setMinimumSize(new java.awt.Dimension(200,200));
    }

}
I
的值不等于
p
时,我想在第二个窗口中重置
JLabel
,这意味着在第一个窗口中单击了按钮


但是,当单击按钮时,标签的文本不会更改。

不应在外部修改Swing元素。如果希望在AWT事件线程中执行代码,可以使用

比如:

SwingUtilities.invokeLater(new Runnable() {
    @override
    public void run() {
        //Swing stuff here.
    }
});

会让你非常接近。

有许多潜在的问题

  • 过度使用/依赖
    静态
  • 摆动线程冲突
  • 变量的线程内存访问
  • 而且总体设计很差
static
没有帮助,从长远来看可能会导致各种问题
static
不是一种跨对象通信机制,您应该学习在没有它的情况下处理的其他技术

Swing是单线程框架,它不是线程安全的,这基本上意味着您不应该在事件调度线程的上下文中执行长时间运行的任务,也不应该从EDT上下文之外修改UI的状态(比如从另一个线程设置标签的文本)

线程
s中访问变量可能会有问题,因为
线程
可以获得自己的变量副本,这意味着线程之间对变量的读写可能会延迟,这意味着它们可能看不到最新的值。通常,您可以使用
volatile
关键字或使用原子API(如
AtomicInteger
)来解决这个问题,但我认为,如果设计得稍微好一点,就可以避免这些需求

现在,您可以使用
SwingWorker
或Swing
计时器
,这两种方法都提供了以保存方式控制EDT更新的解决方案,但您仍然使用线程

您的程序正遭受着基本的糟糕设计,您将一堆属性暴露于不受控制的修改和访问中,这使得解决类的责任(谁可以做什么,什么时候做)变得困难

首先,我要定义一些控件

public interface Counter {
    public int getCount();
    public void setText(String text);
}
这个简单的接口提供了对当前
count
值的访问,并为另一个类提供了设置实现文本的方法。这就是“合同”的定义。这意味着,无论我将此接口的实例传递给谁,他们都只能执行这两项任务,而如何控制这些操作则取决于实现

接下来,我设置
线程

public class ThreadJishu implements Runnable {

    private Counter counter;
    private int initialCount;

    public ThreadJishu(Counter counter) {
        this.counter = counter;
    }
    
    @Override
    public void run() {
        this.initialCount = counter.getCount();
        while (true) {
            if (counter.getCount() !=  initialCount) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                }
                initialCount = counter.getCount();
                counter.setText("After sleep at -> " + initialCount);
            }
            Thread.yield();
        }
    }
}
因此,这与您所做的没有什么不同,只是,我依靠
计数器的实现来完成我需要它完成的工作

最后,实现
计数器
计数器

public class CounterPane extends JPanel implements Counter {

    private int count = 0;
    private JLabel label;
    
    public CounterPane() {
        
        label = new JLabel("Hello");
        JButton btn = new JButton("Click here");
        
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        
        add(label, gbc);
        add(btn, gbc);
        
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count++;
                setText("Button click count = " + count);
            }
        });
        
        Thread t = new Thread(new ThreadJishu(this));
        t.start();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setText(String text) {
        if (EventQueue.isDispatchThread()) {
            label.setText(text);
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setText(text);
                }
            });
        }
    }

}
这为用户提供了界面,并定义了
计数器的工作方式。在
setText
方法中,我们有一个安全防护装置,确保对
JLabel
的所有修改都是在EDT的上下文中完成的,为了简单起见,
JButton
ActionListener
实际上也使用了
setText
方法

可运行的示例

并发性从一开始就是一个复杂的主题,Swing API(与大多数GUI API一样)的需求使得并发性变得更加复杂

看看:

有关常见问题的更多详细信息和可能的解决方案

Swing
计时器
示例。。。 以及一个使用Swing
定时器的简单实现,不需要
线程

public class CounterPane extends JPanel implements Counter {

    private int count = 0;
    private JLabel label;

    private Timer timer;

    public CounterPane() {

        label = new JLabel("Hello");
        JButton btn = new JButton("Click here");

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        add(label, gbc);
        add(btn, gbc);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count++;
                setText("Button click count = " + count);
                timer.restart();
            }
        });

        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setText("After sleep at -> " + getCount());
            }
        });
        timer.setRepeats(false);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setText(String text) {
        label.setText(text);
    }

}

这可能是因为在项目中使用了相同的变量,所以会发生concurreny。尝试将变量i设置为label_线程类中的volatile,Swing组件只能在AWT事件调度线程中修改。在任何其他线程中修改它们将导致不可预测的行为。此外,从多个线程访问的变量,如
label\u thread.i
,需要标记为
volatile
。(您的try/catch应该在循环的周围,而不是循环的内部。)
public class CounterPane extends JPanel implements Counter {

    private int count = 0;
    private JLabel label;

    private Timer timer;

    public CounterPane() {

        label = new JLabel("Hello");
        JButton btn = new JButton("Click here");

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        add(label, gbc);
        add(btn, gbc);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count++;
                setText("Button click count = " + count);
                timer.restart();
            }
        });

        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setText("After sleep at -> " + getCount());
            }
        });
        timer.setRepeats(false);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setText(String text) {
        label.setText(text);
    }

}