咱們知道,在java中線程實現有兩種方法,第一是繼承Thread,第二是實現Runnable接口。不管哪一個,都要重寫run()方法,因爲是重寫,並且run()的定義:public abstract void run(),顯而易見,這個函數式、是沒有返回值的。那麼怎樣獲取線程執行後的結果?java
讓咱們來看一個例子
編程
package com.lu.util; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Scanner; /** * 網絡通用類 * * @author lu * */ public class NetWorkUtil { /** * 從給定的url頁面獲取頁面內容 * * @param urlAddr * @return * @throws Exception */ public String getPageContent(String urlAddr) throws Exception { HttpURLConnection httpURLConn = null; InputStream input = null; Scanner scanner = null; try { URL url = new URL(urlAddr); httpURLConn = (HttpURLConnection) url.openConnection(); httpURLConn.setDoInput(true); httpURLConn.setRequestMethod("GET"); httpURLConn.connect(); input = httpURLConn.getInputStream(); scanner = new Scanner(input); StringBuffer strBuf = new StringBuffer(); while (scanner.hasNextLine()) { strBuf.append(scanner.nextLine()); } return strBuf.toString(); } finally { if (null != scanner) { scanner.close(); } if (null != input) { input.close(); } if (null != httpURLConn) { httpURLConn.disconnect(); } } } } //若是不瞭解URL、URLConnection,你們能夠跳過不看,只需知道,若是調用該方法,就是獲取給定url的頁面內容便可。 package com.lu.callback; import com.lu.util.NetWorkUtil; /** * 該線程負責獲取給定url頁面的內容 * * @author lu * */ public class GetPageContentThread implements Runnable { NetWorkUtil util = new NetWorkUtil(); public String pageContent; public String urlAddr; public GetPageContentThread(String urlAddr) { this.urlAddr = urlAddr; } @Override public void run() { try { //獲取頁面內容 pageContent = util.getPageContent(urlAddr); } catch (Exception e) { e.printStackTrace(); } } } package com.lu.callback; public class Client { public static void main(String[] args) { String url = "http://www.baidu.com"; GetPageContentThreadtr = new GetPageContentThread(url); new Thread(tr).start(); System.out.println(tr.pageContent.length()); } }
客戶端開啓線程並啓動,一次來獲取百度首頁的內容。可是運行一下會發現程序拋出java.lang.NullPointerException異常。爲何呢?你們不要忘了這是在多線程環境下。若是執行System.out.println(tr.pageContent.length());的時候,獲取頁面的線程尚未得到時間片去執行,那麼pageContent確定爲null,那麼拋出異常就是毫無疑問了。設計模式
若是把客戶端代碼改爲這樣,那麼問題就解決了。網絡
package com.lu.callback; public class Client { public static void main(String[] args) { String url = "http://www.baidu.com"; ThreadResult tr = new ThreadResult(url); new Thread(tr).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tr.pageContent.length()); } }
主線程開啓另外一個線程後,休眠1秒鐘,讓給其餘線程去執行。等主線程得到時間片去執行時,頁面內容已經得到。可是存在一個更大的問題,休眠的時間怎麼肯定,若是休眠1秒,獲取頁面的時間爲800毫秒,就白白浪費了CPU的資源。因此確定有更好的辦法,那就是回調。下面直接看代碼。多線程
package com.lu.callback; /** * 該接口定義了process方法,改方法爲回調調用的方法。 * @author lu * */ public interface Callback { public void process(Object... objects); } package com.lu.callback; /** * 改類繼承了Callback接口並實現了process()這個回調方法,用於回調並處理 * @author lu * */ public class GetPageContentCallBack implements Callback { public String urlAddr = null; public String pageContent = null; public GetPageContentCallBack(String urlAddr) { this.urlAddr = urlAddr; } @Override public void process(Object... objects) { if (objects != null && objects.length >= 1) { pageContent = (String) objects[0]; } System.out.println(pageContent.length()); } /** * 該方法建立了獲取頁面內容的線程,並把自身當作參數傳給改線程。 */ public void getPageContent() { GetPageContentThread tr = new GetPageContentThread(urlAddr); tr.setCallback(this); new Thread(tr).start(); } } package com.lu.callback; import com.lu.util.NetWorkUtil; /** * 該線程負責獲取給定url頁面的內容 * * @author lu * */ public class GetPageContentThread implements Runnable { private NetWorkUtil util = new NetWorkUtil(); public String pageContent; public String urlAddr; private Callback callback = null; public GetPageContentThread(String urlAddr) { this.urlAddr = urlAddr; } @Override public void run() { try { // 獲取頁面內容 pageContent = util.getPageContent(urlAddr); } catch (Exception e) { e.printStackTrace(); } //這條語句是關鍵所在,當獲取頁面以後,調用處理方法。 callback.process(pageContent); } public void setCallback(Callback callback) { this.callback = callback; } } package com.lu.callback; public class Client { public static void main(String[] args) { String url = "http://www.baidu.com"; GetPageContentCallBack getPageContentCallBack = new GetPageContentCallBack(url); //調用獲取頁面方法 getPageContentCallBack.getPageContent(); } }
首先客戶端調用getPageContent()方法,該方法建立獲取頁面線程並把自身傳遞給該線程,即將自身的引用給了改線程。獲取頁面的線程執行run()方法獲取頁面,等獲取成功後,調用callback的process()方法,並把結果傳遞給他。就這樣獲得了線程執行的結果並作出處理。
app
如今若是有多個對象關注該線程執行後的結果,那改怎麼去通知呢?將其餘想要關注該線程結果的對象都添加到該線程對象中就能夠了,觀察者... 主題... blalalala.... 好像是某個設計模式。ide
參考文獻:java網絡編程函數
小生不才,學術不精,歡迎你們批評指正this