?
在SWT中,通常需要開多個線程來執(zhí)行任務(wù),因為主線程為UI線程,不能用太長的時間來執(zhí)行某個任務(wù),否則會造成失去響應(yīng)的假象。
SWT的線程通信有幾個要注意的地方:
1、工作線程訪問UI線程。不能在非UI線程中直接訪問UI控件的值,要獲得或設(shè)置控件的值必須通過Display對象的asyncExec()或syncExec()函數(shù),一般的使用方法是:
//代碼A:
?
Display?disp?? = ??Display.getDefault();
? if ?(disp? != ? null ?)??{
???disp.asyncExec(
???? new ??Runnable()??{
???? public ?? void ??run()??{
??????? // ?在這里設(shè)置或獲得控件的值?
?}?
}?
);?
}?
?
Display?disp?? = ??Display.getDefault();
? if ?(disp? != ? null ?)??{
???disp.asyncExec(
???? new ??Runnable()??{
???? public ?? void ??run()??{
??????? // ?在這里設(shè)置或獲得控件的值?
?}?
}?
);?
}?
2、內(nèi)部類與外部類的交流。內(nèi)部類調(diào)用外部類局部變量時,該變量必須是final的,這樣在取得控件的值后返回給外部類處理時就比較麻煩。例如,在上面的代碼段中,有個匿名內(nèi)部類實現(xiàn)了Runnable接口,在里面的run()函數(shù)里可以訪問到UI對象,但是,得到了對象的值怎么告訴外面的代碼呢?假如用普通的局部變量傳遞進去,由于是final的,是不能賦值的,所以需要有一個封裝類來把需要返回的變量封裝起來,這個封裝類是final的,但里面的成員變量是可變的,這樣就把內(nèi)部類里得到的東西傳遞到了外部,不過似乎比較麻煩,不知道有沒有更好的辦法。
//代碼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();//假設(shè)text是一個文本框?qū)ο?br />???????//?在這里設(shè)置或獲得控件的值?
????}?
???}?
???);?
}?
//這里就可以對sw.uiValue的值進行訪問
3、線程間的同步。在上面的代碼B中,通過asyncExec()函數(shù)來取得控件的值所需要的時間比較長,如果在后面馬上訪問那些值是得不到的,于是就需要有個同步的問題,即在控件值取得之前先不進行下一步操作。可以通過synchronized塊及wait(),notify()機制來實現(xiàn)同步。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();//假設(shè)text是一個文本框?qū)ο?br />???????//?在這里設(shè)置或獲得控件的值?
????}?
???}?
???);?
}?
//這里就可以對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();//假設(shè)text是一個文本框?qū)ο?/span>
????????????sw.notify();
?????????}
???????//?在這里設(shè)置或獲得控件的值
?
????}?
???}?
???);?
}
synchronized(sw){
??sw.wait();
}?
//這里就可以對sw.uiValue的值進行訪問
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();//假設(shè)text是一個文本框?qū)ο?/span>
????????????sw.notify();
?????????}
???????//?在這里設(shè)置或獲得控件的值
?
????}?
???}?
???);?
}
synchronized(sw){
??sw.wait();
}?
//這里就可以對sw.uiValue的值進行訪問
但是這里會帶來一個問題,假如很快就能取得控件的值,但后面還有很長一段時間才會用到該值,如果把sw.wait()語句放在比較后的地方,就有可能造成死鎖,因為sw已經(jīng)被notify之后才開始wait的,再沒有其他線程來notify它了,它就只能一直wait下去……。為了解決這個問題,可以(1)把sw.wait()緊跟在disp.asyncExec()后面;(2)給wait()設(shè)置一個timeout參數(shù),到了一定的時間還沒有東西notify它,它就自己超時。但這兩種辦法似乎都比較牽強,沒有十足的保證,JDK文檔里面有個例子,是用while來判斷是否已經(jīng)達到了要求,如果已經(jīng)達到了就不再wait。
//代碼D:
class?StringWrapper?{
???public?String?uiValue;
???public?boolean?isValueSet;//是否已經(jīng)取得了控件的值
}
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();//假設(shè)text是一個文本框?qū)ο?/span>
????????????sw.isValueSet?=?true;
????????????sw.notify();
?????????}
???????//?在這里設(shè)置或獲得控件的值
?
????}?
???}?
???);?
}
synchronized(sw){
??while(!sw.isValueSet){
????try{
??????sw.wait();
????}catch?(InterruptedException?e){
????}
??}
}?
//這里就可以對sw.uiValue的值進行訪問
class?StringWrapper?{
???public?String?uiValue;
???public?boolean?isValueSet;//是否已經(jīng)取得了控件的值
}
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();//假設(shè)text是一個文本框?qū)ο?/span>
????????????sw.isValueSet?=?true;
????????????sw.notify();
?????????}
???????//?在這里設(shè)置或獲得控件的值
?
????}?
???}?
???);?
}
synchronized(sw){
??while(!sw.isValueSet){
????try{
??????sw.wait();
????}catch?(InterruptedException?e){
????}
??}
}?
//這里就可以對sw.uiValue的值進行訪問