求解线程问题

caolixing 2005-11-15 03:38:44

我写了一个窗口,上面有一个按钮,点击按钮后启用另一个线程做别的事情,同时按钮设为不可用,当被启动的线程完成后,再把这个按钮置为可用状态。

请问应该怎么做?
谢谢
...全文
282 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
caolixing 2005-12-01
  • 打赏
  • 举报
回复
谢谢 pdvv(我爱花猫)

散分
caolixing 2005-12-01
  • 打赏
  • 举报
回复
sorry,各位,好久没来了,问题已经解决了 :)

gemouzhi(gemouzhi),我碰到了异常是:
org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:2691)
at org.eclipse.swt.SWT.error(SWT.java:2616)
at org.eclipse.swt.SWT.error(SWT.java:2587)
at org.eclipse.swt.widgets.Widget.error(Widget.java:381)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:284)
at org.eclipse.swt.widgets.Button.setText(Button.java:602)
at test.Run.run(Run.java:16)
我觉得这个应该是线程异常,现在问题解决了,理解不太深,好像是这样的:

SWT里对控件的管理只能由一个主线程来完成,任何其他线程试图修改控件都会抛出上面这个异常。解决方法就是让其他线程完成工作是,给主线程发一个消息,还是由主线程来完成控件的修改工作。

//主线程
public class MainWindow {

public Outputer out = null;
Object o = new Object();
....
....
....
Button bRun = new Button(shell,SWT.NONE);
registerCallback(bRun, SWT.Selection, this, "doRun");
....
....
....
public void doRun(Event event) {

bRun.setEnabled(false);
// start a new thread to wait
new Thread(new Runnable() {
public void run() {
try {
synchronized (o) {
o.wait();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
display.asyncExec(new Runnable() {
public void run() {
bRun.setEnabled(true);
}
});
}
}).start();

// start outputer processor
new Outputer(o);
}
}


public class Outputer extends Thread
{
String COMMAND = null;
String line;
Process p = null;
Object o = null;

public Outputer(Object o)
{
this.o = o;
start();
}

public void run()
{
//你要作的事情
SomethingYouWantToDo();

synchronized (o)
{
o.notify();
}
}


不知道说清楚没有,反正运行结果是满足我的需求的。








gemouzhi 2005-11-17
  • 打赏
  • 举报
回复
invokeLater是用在线程中对UI的更新。

问楼主:

当被启动的线程完成后,再把这个按钮置为可用状态,没看出这有什么线程不安全。

你所理解的线程不安全是什么意思?
disller 2005-11-17
  • 打赏
  • 举报
回复
看 java thread programming
disller 2005-11-17
  • 打赏
  • 举报
回复
用Swing工具:SwingUtilities.invokeLater();
pdvv 2005-11-17
  • 打赏
  • 举报
回复
楼主,俺又转回来了,我今天刚开始学习使用SWT(不好意思),有点感觉,联想到你的问题,可能对你有帮助。

java语言本身支持多线程,虽然很好但是不利于GUI编程,因为它不能保证图形控件操作的同步。但是在SWT中,采用的是一种简化,通常只允许唯一一个“用户线程”对图形控件进行操作。其他线程中如果调用,就会抛出org.eclipse.swt.SWTException。如果非要这么作,在包org.eclipse.swt.widget.Display中提供方法syncExec(Runnable)、asyncExec(Runnable)方法。

所以,你的程序稍作修改就可以了:

public void widgetSelected(SelectionEvent e)
{
Display.getCurrent().syncExec(new Run(button));

//button.setEnabled(false);我把这句放到了Run.run()中了,为了和button.setEnabled(true);对应


新学SWT,有不懂之处请多指教。

}
caolixing 2005-11-16
  • 打赏
  • 举报
回复
有对swt比较熟悉的吗
caolixing 2005-11-15
  • 打赏
  • 举报
回复
谢谢楼上的几位
pdvv(我爱花猫)和lh8748(LH)的方法我都试过了,swing和awt都是没问题的,但是swt在另一个线程里操作控件的时候会抛异常:
org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:2691)
at org.eclipse.swt.SWT.error(SWT.java:2616)
at org.eclipse.swt.SWT.error(SWT.java:2587)
at org.eclipse.swt.widgets.Widget.error(Widget.java:381)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:284)
at org.eclipse.swt.widgets.Button.setText(Button.java:602)
at test.Run.run(Run.java:16)

我把lh8748(LH)的代码改成SWT的运行就是上面的结果,当然,原本awt的环境是没问题的
修改后的代码如下:
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

class test3
{

public test3()
{

Display display = new Display();
Shell shell = new Shell(display);
shell.setLocation(250, 100);

final Button button = new Button(shell, 0);
button.setBounds(150, 100, 100, 30);
button.addSelectionListener(new SelectionListener() {

public void widgetSelected(SelectionEvent e)
{
new Run(button).start();
button.setEnabled(false);
}

public void widgetDefaultSelected(SelectionEvent e)
{
// TODO Auto-generated method stub

}

});

shell.pack();
shell.open();

while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
System.exit(0);
}

public static void main(String[] args)
{

test3 frame = new test3();

}
}

import org.eclipse.swt.widgets.Button;

class Run extends Thread
{
Button button;

public Run(Button button)
{
this.button = button;
}

public void run()
{
button.setText("running...");
boolean flag = true;
while (flag)
{ //做其它事情;
try
{
Thread.sleep(5000);
}
catch (Exception e)
{
}
flag = false;
}
button.setText("run over.");
button.setEnabled(true);
}
}
lh8748 2005-11-15
  • 打赏
  • 举报
回复
写了个简单的例子,用的AWT,你要的应该是这样吧。
import java.awt.*;
import java.awt.event.*;
class Run extends Thread
{
Button button;
public Run(Button button)
{
this.button = button;
}
public void run()
{
button.setName("running...");
boolean flag = true;
while(flag)
{ //做其它事情;
try
{Thread.sleep(5000);}
catch(Exception e) {}
flag = false;
}
button.setName("run over.");
button.setEnabled(true);
}
}
class test3 extends Frame
{
Button button = new Button("click");
public test3()
{
button.setBounds(150,100,100,30);
button.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
button.setEnabled(false);
new Run(button).start();
}
});
this.setLayout(null);
this.add(button);
}
public static void main(String [] args)
{
test3 frame = new test3();
frame.addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
frame.setSize(400,300);
frame.setVisible(true);
}
}
老無所依 2005-11-15
  • 打赏
  • 举报
回复
SWING里面有个ACTION的嘛,可以实现你说的
pdvv 2005-11-15
  • 打赏
  • 举报
回复
我用的是swing,不过跟这个没有关系。

你自己的线程需要这样:
public class ThreadTimer extends Thread {
public final int STATE_STOPPED = 0;
public final int STATE_RUNNING = 1;
public final int STATE_WAITTING = 2;
private int timerState = STATE_STOPPED;

private boolean bRunning = false;

public void run(){
bRunning = true;
while(bRunning){

setTimerState(STATE_RUNNING);
yield();

doSomething();

setTimerState(STATE_WAITTING);
try{
sleep(N * 1000);
}
catch(Exception e){
e.printStackTrace();
}
}
}

/**
* @param timerState 要设置的 timerState。
*/
public void setTimerState(int timerState) {
this.timerState = timerState;
}

//查询当前运行状态
public int getTimerState(){
return this.timerState;
}

public void doSomething(){}
}


caolixing 2005-11-15
  • 打赏
  • 举报
回复
不行,我试了,对了,我用的是SWT控件,可能跟这个有关。

pdvv(我爱花猫),你是用的swing吗
pdvv 2005-11-15
  • 打赏
  • 举报
回复
肯定可以,因为我做过。大概:

窗口类{
private Thread 你的线程;

private void initialize() {
创建控件
按钮1
……
启动检测线程();
}

//单击按钮后启动你的线程


启动检测线程(){
class RedrawThread extends Thread{
public void run(){
if(别的线程.状态 == null){
设置“按钮1”状态
}
else if(别的线程.状态 == "运行"){
……
}
}
RedrawThread redraw = new RedrawThread();
redraw.start();
}
}

你自己写的那个线程必须定义几种状态。
caolixing 2005-11-15
  • 打赏
  • 举报
回复
谢谢 pdvv(我爱花猫)

但是新开的线程不也是不能改UI的东西吗,同样存在线程安全的问题啊
pdvv 2005-11-15
  • 打赏
  • 举报
回复
可以新开一个线程,用来实时检测程序运行状态、设置UI的状态。
caolixing 2005-11-15
  • 打赏
  • 举报
回复
顶啊,期待高手ing
caolixing 2005-11-15
  • 打赏
  • 举报
回复
lcwlyl(网络幽灵)

帮我想想办法,窗口控件好像不是线程安全的,不能跨线程操作
caolixing 2005-11-15
  • 打赏
  • 举报
回复
我尝试在那个线程结束的时候调用主程序的空间直接改状态,但是报异常了:

Invalid thread access

还有什么方法能解决吗
网络精灵 2005-11-15
  • 打赏
  • 举报
回复
你既然有思路了,就按照你的思路做就行了。

62,629

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧