SWT的线程间通信

在SWT中,通常需要开多个线程来执行任务,因为主线程为UI线程,不能用太长的时间来执行某个任务,否则会造成失去响应的假象。


SWT的线程通信有几个要注意的地方:


1、工作线程访问UI线程。不能在非UI线程中直接访问UI控件的值,要获得或设置控件的值必须通过Display对象的asyncExec()或syncExec()函数,一般的使用方法是:

Java代码
//代码A:  
Display disp = Display.getDefault();  
if(disp != null) {  
    disp.asyncExec(new Runnable() {  
        public void run() {  
            //  在这里设置或获得控件的值    
        }   
    });   
}  

//代码A:
Display disp = Display.getDefault();
if(disp != null) {
disp.asyncExec(new Runnable() {
public void run() {
//  在这里设置或获得控件的值 
}
});


2、内部类与外部类的交流。内部类调用外部类局部变量时,该变量必须是final的,这样在取得控件的值后返回给外部类处理时就比较麻烦。例如,在上面的代码段中,有个匿名内部类实现了Runnable接口,在里面的run()函数里可以访问到UI对象,但是,得到了对象的值怎么告诉外面的代码呢?假如用普通的局部变量传递进去,由于是final的,是不能赋值的,所以需要有一个封装类来把需要返回的变量封装起来,这个封装类是final的,但里面的成员变量是可变的,这样就把内部类里得到的东西传递到了外部,不过似乎比较麻烦,不知道有没有更好的办法。



Java代码
//代码B:  
 
class StringWrapper {  
    public String uiValue;  
}  
 
StringWrapper sw = new StringWrapper();   
Display disp = Display.getDefault();  
if (disp != null )  {  
    disp.asyncExec(new  Runnable()  {  
        public  void  run()  {  
            sw.uiValue = text.getText();//假设text是一个文本框对象  
            // 在这里设置或获得控件的值   
        }   
    });   
}   
//这里就可以对sw.uiValue的值进行访问  

//代码B:

class StringWrapper {
public String uiValue;
}

StringWrapper sw = new StringWrapper();
Display disp = Display.getDefault();
if (disp != null )  {
disp.asyncExec(new  Runnable()  {
public  void  run()  {
sw.uiValue = text.getText();//假设text是一个文本框对象
// 在这里设置或获得控件的值
}
});
}
//这里就可以对sw.uiValue的值进行访问 



3、线程间的同步。在上面的代码B中,通过asyncExec()函数来取得控件的值所需要的时间比较长,如果在后面马上访问那些值是得不到的,于是就需要有个同步的问题,即在控件值取得之前先不进行下一步操作。可以通过synchronized块及wait(),notify()机制来实现同步。

Java代码
//代码C:  
 
class StringWrapper {  
   public String uiValue;  
}  
 
StringWrapper sw = new StringWrapper();   
Display disp = Display.getDefault();  
if (disp != null )  {  
    disp.asyncExec(new  Runnable()  {  
        public  void  run()  {  
            synchronized(sw){  
                sw.uiValue = text.getText();//假设text是一个文本框对象  
                sw.notify();  
            }  
            // 在这里设置或获得控件的值  
        }   
    });   
}  
synchronized(sw){  
    sw.wait();  
}   
//这里就可以对sw.uiValue的值进行访问 

//代码C:

class StringWrapper {
   public String uiValue;
}

StringWrapper sw = new StringWrapper();
Display disp = Display.getDefault();
if (disp != null )  {
disp.asyncExec(new  Runnable()  {
public  void  run()  {
synchronized(sw){
sw.uiValue = text.getText();//假设text是一个文本框对象
sw.notify();
}
// 在这里设置或获得控件的值
}
});
}
synchronized(sw){
sw.wait();
}
//这里就可以对sw.uiValue的值进行访问

但是这里会带来一个问题,假如很快就能取得控件的值,但后面还有很长一段时间才会用到该值,如果把sw.wait()语句放在比较后的地方,就有可能造成死锁,因为sw已经被notify之后才开始wait的,再没有其他线程来notify它了,它就只能一直wait下去……。为了解决这个问题,可以(1)把sw.wait()紧跟在disp.asyncExec()后面;(2)给wait()设置一个timeout参数,到了一定的时间还没有东西notify它,它就自己超时。但这两种办法似乎都比较牵强,没有十足的保证,JDK文档里面有个例子,是用while来判断是否已经达到了要求,如果已经达到了就不再wait。

Java代码
//代码D:  
 
class StringWrapper {  
    public String uiValue;  
    public boolean isValueSet;//是否已经取得了控件的值  
}  
 
StringWrapper sw = new StringWrapper();   
sw.isValueSet = false;  
Display disp = Display.getDefault();  
if (disp != null )  {  
    disp.asyncExec(new  Runnable()  {  
        public  void  run()  {  
            synchronized(sw){  
                sw.uiValue = text.getText();//假设text是一个文本框对象  
                sw.isValueSet = true;  
                sw.notify();  
            }  
            // 在这里设置或获得控件的值  
        }   
    });   
}  
synchronized(sw){  
    while(!sw.isValueSet){  
        try{  
            sw.wait();  
        }catch (InterruptedException e){  
        }  
    }  
}   
//这里就可以对sw.uiValue的值进行访问 

你可能感兴趣的:(jdk,UI)