在实际的应用中,经常一种需要持续的工作,比如我们做过的网络程序中,在客户端需要持续的读取服务器发送过来的消息,在服务器端需要持续的读取客户端发送过来的消息。这种持续性的工作,通常在一个while循环中执行,只有当循环条件不满足的时候,才终止while循环。比如下面的例子:
package thread;
public class NormalObject {
public long runtimes;
public boolean stop;
public NormalObject(){
stop=false;
runtimes=0;
}
public void run(){
int run=0;
while(!stop){
run ++;
if(run>10000){
runtimes ++;
run =0;
}
}
}
}
这是一个普通的对象,当创建对象之后,调用对象的run方法,对象就持续的运行,直到stop这个值变成false的时候,它才停止。就像下面的:
NormalObject normalObject = new NormalObject();
normalObject.stop = false;
normalObject.run();
normalObject对象会一直运行,直到我们把它的stop字段设置为false为止。
但是while循环是非常消耗CPU时间的,一旦运行起来,就会占用大部分的CPU时间,其余的操作几乎没法进行了。比如我们设计如下的一个程序:
创建一个窗口程序,上面有个按钮,显示的是“Start”,当点击它之后,就运行normalObject,同时把“Start”改成“End”,然后再点击一次,就会让normalObject停止,同时把“End”改成“Start”。
我们写出如下的代码:
package ui;
import java.awt.EventQueue;
public class MainFram {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFram window = new MainFram();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MainFram() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final NormalObject normalObject = new NormalObject();
final JButton btnNewButton = new JButton("Start");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//点击按钮,执行逻辑
if (btnNewButton.getText().equals("Start")) {
btnNewButton.setText("End");
normalObject.stop = false;
normalObject.run();
} else {
btnNewButton.setText("Start");
normalObject.stop = false;
}
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}
}
测试运行,可以看到,没法达到我们的目的。
分析一下可以看出,normalObject.run()方法是一直在执行while,所以退不出来,其他的代码也得不到执行,系统出现了“卡死”现象。
这是因为,当我们点击程序开始运行的时候,系统就会创建一个线程,这个线程在执行main方法中的代码,我们的窗体就是在main方法中创建的,所以窗体运行在这个线程上面。当这个线程运行到normalObject.run()的时候,就进入while循环了,别的代码就执行不了了。
对这个问题的解决方法,就是创建另外的一个线程,让那个累加操作(normalObject.run())运行在其他的线程中,它会和main所在的线程并发执行,就不再干扰到窗体中其他的响应了。我们对normalObject修改如下:
package thread;
public class ThreadObject extends Thread {
public long runtimes;
public boolean stop;
public ThreadObject(){
stop=false;
runtimes=0;
}
public void run(){
int run=0;
while(!stop){
run ++;
if(run>10000){
runtimes ++;
run =0;
}
}
}
}
注意:类的名字换了,所以需要新建一个类。
再修改窗体代码如下:
package ui;
import java.awt.EventQueue;
public class MainFram {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFram window = new MainFram();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MainFram() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final ThreadObject normalObject = new ThreadObject();
final JButton btnNewButton = new JButton("Start");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (btnNewButton.getText().equals("Start")) {
btnNewButton.setText("End");
normalObject.stop = false;
normalObject.start();
} else {
btnNewButton.setText("Start");
normalObject.stop = false;
}
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}
}
注意修改的代码我用红色下划线标志出来了,同上面的区别可以比较。
然后在运行,就可以看到达到我们的要求了。
这就是因为,在新的代码中,当执行到normalObject.start()的时候,系统会开辟一个新的同main所在线程并列的线程,然后normalObject中run()方法中的代码就跑到新的线程中去运行了,从而使得main所在线程继续能执行下面的代码了。