【賽迪網(wǎng)技術(shù)社區(qū)整理】在進(jìn)行多線程編程中,比較重要也是比較困難的一個(gè)操作就是如何獲取線程中的信息。大多數(shù)人會(huì)采取比較常見的一種方法就是將線程中要返回的結(jié)果存儲(chǔ)在一個(gè)字段中,然后再提供一個(gè)獲取方法將這個(gè)字段的內(nèi)容返回給該方法的調(diào)用者。如以下的ReturnThreadInfo類:
package threadtest1;
/**
*
* @author shi mingxiang
*/
public class ReturnThreadInfo extends Thread {
private String str;
public ReturnThreadInfo() {
this.str = "Hello";
}
public void run(){
this.str = "Hello World!";
}
public String getThreadInfo(){
return this.str;
}
}
大家可以看到該類是一個(gè)線程類并含有一個(gè)初始值為"Hello"的字段str以及一個(gè)可以返回str值的方法:getThreadInfo(),而且當(dāng)這個(gè)線程啟動(dòng)后str會(huì)被賦于新值:"Hello World!"。現(xiàn)在我想在另外一個(gè)類中啟動(dòng)ReturnThreadInfo線程,并通過(guò)getThreadInfo()方法獲取值為"Hello World!"的變量并打印輸出到控制臺(tái)中。以下給出一個(gè)實(shí)現(xiàn)該功能的Main類:
package threadtest1;
/**
*
* @author shi mingxiang
*/
public class Main{
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ReturnThreadInfo returnThreadInfo = new ReturnThreadInfo();
returnThreadInfo.start();//創(chuàng)建并啟動(dòng)ReturnThreadInfo線程
System.out.println(returnThreadInfo.getThreadInfo());//獲取并輸出returnThreadInfo對(duì)象的str的值
}
}
以上是一個(gè)多數(shù)熟悉單線程編程的人在反應(yīng)下給出的實(shí)現(xiàn)方法。但是該類在運(yùn)行的時(shí)候輸出的結(jié)果卻不是期望的"Hello World!"而是"Hello",這是由于線程的競(jìng)爭(zhēng)條件導(dǎo)致的(由于ReturnThreadInfo線程和Main線程的優(yōu)先級(jí)都為5,所以在很大幾率上ReturnThreadInfo線程的run()方法還沒(méi)有運(yùn)行,Main類就已經(jīng)運(yùn)行System.out.println(returnThreadInfo.getThreadInfo());將"Hello"輸出了。具體的原理可以參見另一篇文章:"java多線程的幾點(diǎn)誤區(qū)")。有的人可能會(huì)立即想到把ReturnThreadInfo線程的優(yōu)先級(jí)設(shè)高些(比如的10)就可以returnThreadInfo線程的run()方法先運(yùn)行完,然后Main類的System.out.println(returnThreadInfo.getThreadInfo())再運(yùn)行,這樣輸出的結(jié)就一定是期望的"Hello World!"了。這種通過(guò)調(diào)整線程優(yōu)先級(jí)的方法固然可以在某種程度上解決該問(wèn)題,但是線程爭(zhēng)用CPU運(yùn)行時(shí)間的原理卻決不僅僅只是優(yōu)先級(jí)高低的原因(優(yōu)先級(jí)高的線程并不意味著一定比優(yōu)先級(jí)低的線程先運(yùn)行,只是幾率要更大一些)。你并不希望ReturnThreadInfo線程9999次都比Main先運(yùn)行,卻在關(guān)鍵的一次在Main之后再運(yùn)行。因此下面給出兩種比較常見的獲取線程信息的方法:
一、輪詢
比較常見的一種解決方案是,讓線程類獲取方法在結(jié)果字段設(shè)置之前返回一個(gè)標(biāo)志值。然后主線程定時(shí)詢問(wèn)獲取方法,看是否返回了標(biāo)志之外的值。以下給出了具體的實(shí)現(xiàn)方法,該方法不斷測(cè)試str的值是否為"Hello",如果不為"Hello"才打印輸出它。例如:
package threadtest1;
/**
*
* @author shi mingxiang
*/
public class Main{
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ReturnThreadInfo returnThreadInfo = new ReturnThreadInfo();
returnThreadInfo.start();//創(chuàng)建并啟動(dòng)ReturnThreadInfo線程
while(true){
String str = returnThreadInfo.getThreadInfo();
if(!str.equals("Hello")){
System.out.println(returnThreadInfo.getThreadInfo());
break;
}
}
}
}
這種方案雖然能起到作用,但是它做了大量不需要做的工作。事實(shí)上,還有一種更簡(jiǎn)單有效的方法來(lái)解決這個(gè)問(wèn)題。
二、回調(diào)
輪詢方法的特點(diǎn)是主類Main不斷詢問(wèn)線程類是否結(jié)束,這實(shí)際上大量浪費(fèi)了運(yùn)行時(shí)間,特別是當(dāng)線程特別多的時(shí)候。因此如果反過(guò)來(lái)在線程結(jié)束時(shí),由線程自己告訴主類Main線程已經(jīng)結(jié)束,然后Main再獲取并輸出str的值,這樣就避免了輪詢方法所帶來(lái)的不必要的系統(tǒng)開銷問(wèn)題。
在具體的實(shí)現(xiàn)過(guò)程中,線程可以在結(jié)束時(shí)通過(guò)調(diào)用主類中的一個(gè)方法來(lái)實(shí)現(xiàn)告知功能,這種方法叫做回調(diào)。這樣主類Main就可以在等待線程結(jié)束時(shí)休息,也就不會(huì)占用運(yùn)行線程的時(shí)間。下面是修改后的Main類:
public class Main{
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ReturnThreadInfo returnThreadInfo = new ReturnThreadInfo();
returnThreadInfo.start();
}
public static void receiveStr(String str){
System.out.println(str);
}
}
相比于前面,我們?cè)贛ain類中添加了一個(gè)靜態(tài)方法receiveStr(String str),該方法是供線程結(jié)束之前調(diào)用,通過(guò)參數(shù)str將要返回的線程信息返回給Main類并輸出顯示出來(lái)。下面是修改后的ReturnThreadInfo類,該類在線程結(jié)束前回調(diào)了Main.receiveStr方法,通知線程已結(jié)束。
package threadtest1;
/**
*
* @author shi mingxiang
*/
public class ReturnThreadInfo extends Thread {
private String str;
public ReturnThreadInfo() {
this.str = "Hello";
}
public void run(){
this.str = "Hello World!";
Main.receiveStr(str); //回調(diào)receiveStr方法
}
}
如果有很多個(gè)對(duì)象關(guān)心線程的返回的信息,線程可以保存一個(gè)回調(diào)對(duì)象列表。某個(gè)對(duì)象可以通過(guò)已經(jīng)定義的一個(gè)對(duì)象將自己添加到列表中,表示自己對(duì)這些信息的關(guān)注。如果有多個(gè)類的實(shí)例關(guān)心這些信息,也可以定義一個(gè)interface,在interface中聲名回調(diào)方法,然后這些類都實(shí)現(xiàn)這個(gè)接口。其實(shí)這是典型的java處理事件的方法,這么做可以使得回調(diào)更靈活,可以處理涉及更多線程、對(duì)象和類的情況。稍后會(huì)給出這種模仿事件處理模型的回調(diào)的實(shí)現(xiàn)方法。
Java基礎(chǔ) 獲取java線程中信息的兩種方法
更新時(shí)間: 2008-04-10 14:16:14來(lái)源: 粵嵌教育瀏覽量:837
粵嵌動(dòng)態(tài)
推薦閱讀
- ·佛山市冠宇達(dá)電源有限公司專場(chǎng)招聘會(huì)(長(zhǎng)沙校區(qū))
- ·北京朝歌數(shù)碼科技股份有限公司專場(chǎng)招聘
- ·深圳研賽自動(dòng)化設(shè)備公司專場(chǎng)招聘(長(zhǎng)沙校區(qū))
- ·深圳市興禾自動(dòng)化股份有限公司專場(chǎng)招聘(長(zhǎng)沙校區(qū))
- ·中山市弘億實(shí)業(yè)有限公司專場(chǎng)招聘會(huì)
- ·東莞市德聲實(shí)業(yè)有限公司專場(chǎng)招聘
- ·深圳華創(chuàng)智聯(lián)電子有限公司專場(chǎng)招聘
- ·廣州2512全網(wǎng)運(yùn)營(yíng)就業(yè)班
- ·廣州2511嵌入式開發(fā)就業(yè)班
- ·深圳市領(lǐng)世達(dá)科技有限公司專場(chǎng)招聘