问题描述
请查看下面的代码.
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
,这意味着在第一个窗口中单击了按钮.
I want to reset the JLabel
in the 2nd window when the value of i
is not equals to p
that means the button is clicked in 1st window.
但是当单击按钮时,JLabel
的文本不会更改.
But when button is clicked JLabel
's text is not being changed.
推荐答案
存在许多潜在问题;
- 过度使用/依赖
static
- 违反摆动线程
- 变量的线程内存访问
- 一般的不良设计.
- Overuse/reliance on
static
- Swing thread violations
- Thread memory access of variables
- And general poor design.
static
并没有帮助,从长远来看可能会引起各种各样的问题. static
不是跨对象通信机制,如果没有它,您应该学习其他处理方法
static
is not helpful and can cause all sorts of issues in the long run. static
is not a cross object communication mechanism and you should learn other techniques for dealing without it
Swing是单线程框架,并且不是线程安全的,这基本上意味着您不应在事件调度线程的上下文中执行长时间运行的任务,并且也不应在以下情况的上下文之外修改UI的状态: EDT(例如从另一个线程设置标签文本).
Swing is single threaded framework and it is not thread safe, this basically means that you should not perform long running tasks within the context of the Event Dispatching Thread and you should also not modify the state of the UI from outside the context of the EDT (like setting the text of the label from another thread).
从Thread
内部访问变量并存在问题,因为Thread
可以获取其自己的变量副本,这意味着可以在线程之间延迟对变量的读写,这意味着它们可能看不到最新值.通常,您可以使用volatile
关键字或使用原子API(例如AtomicInteger
)来解决此问题,但是我认为采用更好的设计可以避免这些需求.
Accessing variables from within Thread
s and be problematic, as the Thread
can get it's own copy of the variable, this means that reads and writes to the variable can be delayed between threads, meaning that they may not see the latest value. Typically, you can resolve this with the volatile
keyword or using the atomic API, like AtomicInteger
, but I think with a little better design, you can avoid these needs.
现在,您可以使用SwingWorker
或Swing Timer
,它们都提供了以保存方式控制对EDT更新的解决方案,但是您仍然可以使用线程.
Now, you could use a SwingWorker
or a Swing Timer
, both of which provide solutions to controlling updates to the EDT in a save way, but you also still use a thread.
您的程序正遭受基本的不良设计之苦,您将一堆属性暴露给不受控制的修改和访问,从而难以解决类的职责(谁可以做什么,什么时候做什么).
You program is suffering from basic poor design, you're expose a bunch of properties to uncontrolled modifications and access, making it difficult to resolve the responsibilities of the classes (who can do what and when).
因此,首先,我将定义一些控件
So, to start with, I'm going to define some control
public interface Counter {
public int getCount();
public void setText(String text);
}
这个简单的接口提供对当前count
值的访问,并为另一个类提供了一种设置实现文本的方法.这定义了合同".这意味着,无论我将这个接口的实例传递给谁,他们都只能执行这两个任务,并且要由实现来决定如何控制这些动作
This simple interface provides access to the current count
value and provides a means for another class to set the text of the implementation. This defines the "contract". This means that who ever I pass an instance of this interface to, they can only perform those two tasks and it's up to the implementation to decide how those actions are controlled
接下来,我设置Thread
....
Next, I setup the Thread
....
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();
}
}
}
所以,这与您所做的没什么不同,除了,我依靠Counter
的实现来完成我需要它执行的工作.
So, this isn't that different from what you were doing, except, I'm relying on the implementation of Counter
to do the work I need it to do.
最后是Counter
,CounterPane
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);
}
});
}
}
}
这为用户提供了界面,并定义了Counter
的工作方式.在setText
方法中,我们有一个安全保护措施,可确保对JLabel
的所有修改都是在EDT的上下文内完成的,并且为简单起见,JButton
的ActionListener
实际上使用了setText
方法.
This provides the interface to the user as well as defines the workings of the Counter
. In the setText
method, we have a safe guard which ensures that all modifications to the JLabel
are done from within the context of the EDT and for simplicity, the JButton
's ActionListener
actually uses the setText
method as well.
可运行的示例...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LabelThread {
public static void main(String[] args) {
new LabelThread();
}
public LabelThread() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CounterPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Counter {
public int getCount();
public void setText(String text);
}
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);
}
});
}
}
}
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();
}
}
}
}
并发是一门很复杂的主题,并因Swing API(如大多数GUI API)的需要而变得更加复杂.
Concurrency is a complex subject to begin with, made more complicated by the needs of the Swing API (like most GUI APIs).
看看:
- Concurrency in Swing
- Worker Threads and SwingWorker
- How to use Swing Timers
有关常见问题的更多详细信息和可能的解决方案
for more details and possible solutions for common problems
这是使用Swing Timer
的简单实现,不需要Thread
And a simple implementation using a Swing Timer
, no Thread
's required
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);
}
}
这篇关于Swing中的Thread和JLabel-无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!