回調的實現--java

咱們知道,在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

相關文章
相關標籤/搜索