Java 併發(Future 模式)

>Future 提前完成任務

首先,梳理一下,多線程爲我們帶來什麼:

  • 充分利用CPU
  • 當我們需要並行處理一件任務(並不一定是爲了提高運算速度,而且很多時候性能並不是絕對的問題,同一時間需要處理多個任務,就要開線程)

Future,未來,什麼是未來?

設想一種情景,線程等待生產產品的時候,想做點其他的事情

產品:

public class Product {
	private int id;
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Product [id=" + id + ", name=" + name + "]";
	}

	public Product() {

	}

	public Product(int id, String name) {
		this.id = id;
		this.name = name;
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					// 模擬產品生產過程
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
		
	}
}

生產工廠:

public class ProductFactory {
	public Product buildProduct() {
		return new Product();
	}
}

測試線程:

public class Go {

	public static void main(String[] args) {
		ProductFactory pf=new ProductFactory();
		System.out.println("準備生產產品");
		Product product = pf.buildProduct();
		System.out.println("生產產品的時候,我想幹點別的...");
		System.out.println("產品生產完畢"+product);
	}
}

結果:

準備生產產品
生產產品的時候,我想幹點別的...
產品生產完畢Product [id=1, name=tea]

上面的代碼的問題?

首先,爲了模擬產品構建比較慢,我們使用Thread.sleep(),然後我們將Thread.sleep() 又放到了一個線程中,這是一種錯誤的代碼,真正模擬生產產品,也就是初始化賦值的代碼並沒有辦法拿到線程裏面;

如果不能開線程,那麼在真正產品生產結束之前,線程真就不能幹點別的。

另外,在構造函數中不能開線程,會造成This 逃逸現象(在對象構造完成之前,就發佈了引用)。

再來,新問題:

如果現在要去蛋糕店定做一個蛋糕,蛋糕製作期間,想先處理下其他事情,先拿到訂單,做好之後再拿到實際的蛋糕

建立模型:

爲什麼要設計成這個樣子,首先找老闆要定做一個蛋糕,需要一個返回值,老闆一開始只能給我一個訂單,蛋糕和訂單 並不是同一個類型,所以要同時繼承一個接口/共同繼承一個類,這樣滿足類之間的多態。

其中訂單中對蛋糕存在一種包裝,存在依賴關係,真正幹活的還得是Real。

之前你拿蛋糕是直接在那等着做好了,直接拿蛋糕,現在有了這層 “訂單包裝”之後,既方便“老闆”先給你一個訂單,然後開線程把一個未完成的“訂單”完成,同時你去做其他事情,也可以通過“訂單”這個包裝來控制:

  • 蛋糕未做完之前,來取就得等待,等做好了就通知你取“蛋糕”。
  • 蛋糕做好之後來取,直接就可以獲得蛋糕。
/**
 * 數據訪問接口
 */
public interface Data {
	public String obtainString();
}
/**
 * 類似於產品 實際數據 "蛋糕"
 */
public class Real implements Data {
	public Real() {
		try {
			//模擬產品生產過程
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public String obtainString() {
		//一旦可以調用返回,即代表產品生產完成
		return "hello world";
	}
}
/**
 * 可以理解爲 "訂單"
 */
public class Future implements Data {
	private Real real;
	private boolean ready = false;

	public synchronized void setReal(Real real) {
		if (ready) {
			return;
		}
		this.real = real;
		this.ready = true;
		notifyAll();
	}

	@Override
	public synchronized String obtainString() {
		if (!ready) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return real.obtainString();
	}
}
/**
 * 返回Data對象  可以理解爲 "蛋糕店"
 */
public class RequestHandler {
	public Data requestData() {
		final Future future = new Future();
		//開了一個線程去 做"蛋糕",可以想象這個線程需要運行一段時間
		new Thread(new Runnable() {
			@Override
			public void run() {
				Real real = new Real();
				future.setReal(real);
			}
		}).start();
		//先給你一個訂單
		return future;
	}
}
public class Go {

	public static void main(String[] args) throws InterruptedException {
		RequestHandler handler = new RequestHandler();
		//這裏向"老闆"handler 請求做蛋糕 ,拿到訂單
		Data data1 = handler.requestData();
		Data data2 = handler.requestData();
		
		/**
		 * 這裏我們可以做其他事情,而不是等待
		 */
		System.out.println("我在做其他事情...");
		// Thread.sleep(3000);
		System.out.println(data1.obtainString());
		System.out.println(data2.obtainString());
	}
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章