2011年9月11日 星期日

Java Swing 的多執行緒(二)

執行緒有點複雜。

3、工人執行緒和SwingWorker

當Swing程式需要長時間的工作時,通常是使用Worker Thread(工人執行緒),也就是背景執行緒,由工人執行緒執行的工作,都是javax.swing.SwingWorker的實體,SwingWorker是虛擬類別,匿名內層類別可以很方便的建立SwingWorker物件。

SwingWorker提供一些有用的特性:

  • SwingWorker子類別可以定義done()方法,當背景工作完成後,EDT會自動呼叫這個方法。
  • SwingWorker實作java.util.concurrent.Future,這個介面允許背景程式提供一個傳回值給其他的執行緒,這個介面的其他方法,可以取消背景工作,或偵測背景工作正在執行或被取消了。
  • 藉由呼叫SwingWorker.publish(),背景工作可以提供中間結果,呼叫方法可以使EDT去呼叫SwingWorker.process()方法。
  • 背景工作可以定義綁定的屬性,當綁定的屬性改變時,會觸發事件,造成EDT去執行處理事件的方法。

所以可以得知,當SwingWorker的執行緒在執行背景工作時,有很多的時機會可以觸發EDT去執行SwingWorker的方法,或是屬性改變事件處理方法。

另外,SwingWorker物件是不可重用的,每次執行都必須建立一個新的實體。

4、背景工作範例

下面的範例是背景載入圖片:

SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
@Override
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
for (int i = 0; i < nimgs; i++) {
innerImgs[i] = loadImage(i+1);
}
return innerImgs;
}

@Override
public void done() {
//Remove the "Loading images" label.
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};


SwingWorker的子類別必須實作doInBackground()方法,可以選擇性的實作done()方法,要提醒的是,down()方法是由EDT所執行。

SwingWorker是泛型型別,有2個型別參數,第一個參數指定doInBackground()方法返回的型別,也是get()方法返回的型別,其他的執行緒,可以透過get()方法,取得doInBackground()所傳回的物件。第2個型別參數,是當doInBackground()還在執行時,所傳回的暫時性物件。範例沒有傳回值,所以是Void型別。

另外,為什麼要用done()方法設定imgs,而不直接在doInBackground()方法中設定,因為imgs參考到在工人執行緖建立的物件,而要在EDT使用這些物件。當不同執行緖共享物件時,要確定物件被一個執行緒改變時,另外一個執行緒要能得知改變,就要使用這樣的方法。使用get()方法可以保證這樣的狀況,這是因為get()方法會在建立imgs的程式碼和使用imgs的程式碼之間,建立「在之前發生」(happen-before)關係。

有2種方法可以取得doInBackground()所傳回的物件:


  • SwingWorker.get(),且沒有參數,如果doInBackground()還沒結束,執會停住,等到結束。

  • SwingWorker.get(),並傳入一個timeout參數,如果doInBackground()還沒結束,會停住等待,或是等到timeout,並丟出java.util.concurrent.TimeoutException。

要注意,如果在EDT中呼叫get()方法,GUI會停住,直到get()方法返回。所以確定背景工作完成後,再呼叫get()方法。

2011年9月6日 星期二

Java Swing的多執行緒(一)

在研究NetBeans的過程式,突然需要用到多執行緒的功能,對於專業程式設計師而言,多執行緒的程式可能稀鬆平常,但對於半調子的我,可從來沒有深入研究過。
為求速成,只好求助官方教學檔Concurrency in Swing,後續的內容都是從官方教學中精減出來,主要是快速讓自己能對Java 多執行緒有基本的瞭解。

1、Swing多執行緒

一個Swing程式,包含3種執行緖。一個是Initial threads(初始執行緖),用於執行應用程式一開始的程式碼。另外一個是event dispatch thread(EDT)(事件分派執行緖),所有事件處理的程式碼都是這個執行緖執行,大多數和Swing框架互動的程式碼也是有這個執行緖所執行。再來是Worker thread(工人執行緖)也稱為background thread(背景執行緖),比較耗時的背景工作都由這個執行緖執行。
程式設計師並不需要提供程式碼明確的建立這些執行緖,它們由Swing框架或執行時期容器所提供,程式設計師只需要使用這些執行緖建立互動及可維護的Swing應用程式。

2、初始執行緖

每個應用程式一開始都會有一組初始的執行緒,對於普通Java程式,只有一個初始執行緒,用於執行main()方法,對於applet而言,初始執行緒會建立applet物件並呼叫init()和start()方法,這些初始執行緒可能是一個也可能是多個,要視Java執行時期容器的實作而定。
對於Swing應用程式,初始執行緖最基本的工作是建立一個Runable物件,這個物件用於初始化GUI,並排程由EDT所執行的物件。一但GUI建立後,應用程式主要由GUI事件驅動,這些事件是由EDT所執行的短暫工作,應用程式可以排程EDT所執行的工作,由EDT所執行的工作應該是越短越好,也可以執行較長的工作,也就是工人執行緖。
初始執行緖透過javax.swing.SwingUtilities.invokeLater() 或 javax.swing.SwingUtilities.invokeAndWait()等2個方法,處理建立GUI的工作,這2個方法都只有一個參數,一個Runnable物件,這個2方法的不同處是,invokeLater()只排程工作然後就返回(return),而invokeAndWait()會等到工作完成再返回。

SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    createAndShowGUI();
  }
});

對於applet而言,GUI的工作是由init()方法透過invokeAndWait()所建立,如果不這樣做,init()可能會在GUI建立之前返回,會造成瀏覽器啟動applet會有問題,而對於一般的GUI程式,建立GUI物件通常是初始執行緖所執行的唯一工作,所以使用invokeLater()或invokeAndWait()都可以。
為什麼初始執行緖只建立GUI物件,因為所有建立及與Swing元件互動的程式碼都是透過EDT所執行,這是很重要的限制。

2011年8月31日 星期三

工人物語7 第8關心得

今晚第8關終於過了,不過過關過得有的莫明奇妙。這次不像第7關這麼笨,浪費很多時間在嘗試,先上網找別人的心得,不過遊戲的樂趣就在嘗試各種過關方式,還是分享我的過法吧。
如同網友分享的一樣,這一關叫作牧師大賽,因為有一個敵人是大主教,所以很快就會研發科技,而研發科技總共有4點聲望,搶到這4點聲望對於勝利是有好處的,加上我本身就是喜歡發展,所以就採用牧師大賽的玩法。而且遊戲設定似乎也是這樣子,不然一開始就給50份食物幹什麼?
所以一開始就是以發展教堂為建設目標,其實是發展牧師搶研發,這裡就不細說建設過程,必竟還是要留點嘗試的樂趣,但提示一下,訓練1牧師要2份食物加上1份的啤酒還有要佔1個住宅空間,而遊戲一開始只有50份食物,而其他是不足的,所以當等待教堂建設時,別忘了製造啤酒的生產鍊要趕上,而且住宅空間要有。在試驗的過程中,有時後是啤酒趕不上,不然就是住宅不夠,又要等建房子,造成敵人先研發科技了。
一開始訓練出牧師後,首先要搶那4點有聲望的科技,我試了幾次,最好的成績是只有伐木的科技被大主教研發了,其他的都搶到研發成功。
這關有很多中立城堡,也是用牧師去搶領土,另外兩個任務勝利點,也可以用牧師去搶。
最後別忘了貿易路線,這一關可以用衣服、布料和毛線換金幣,錢多也可以得到勝利點數,當然要先建立貿易路線。
綜合上述,不小心,就得到5點勝利點了,過關過程只打了一場仗。好在有建軍營,補了幾個兵,所以沒有輸。

2011年8月27日 星期六

工人物語7 倉庫與物流

在網路上找到一篇討論倉庫與物流的文章,叫作物流系統初探,出處是那也不知道,但是很有用。所以轉貼過來,並註記一些自己的心得,供自己參考。

一、倉庫的專屬性:

工人物語7的倉庫可以隨便建。但是,這個倉庫絕對不能亂建,更不是越多越好。為什麼呢?請你把鼠標左擊隨便一家工業或者農業,你會發現兩條線,1條連接此建築的工人,另一條連接的是一個倉庫,這個倉庫就是這個建築的專屬倉庫!也就是這個建築(工廠)所需的一切,都由這個倉庫提供,從食物到原料。如果此倉庫沒有所需要的物品, 那麼倉庫服務的3個工人就會去其他倉庫取。

系統默認離建築最近的倉庫是專屬倉庫,而且未升級前,一個倉庫一種貨物限定只能放20個。倉庫滿了,工廠生產會也會停止的,所以不止是缺食物才會停止生產。

二、倉庫的最低保障:

在工人物語7里面,倉庫有一個最低保障制度。倉庫會優先保證老客戶的物資供應,然後再考慮新客戶。如果物資短缺,那麼新客戶就會直接被拒之門外,直到物資滿足為止。這個物資包括生產原料和食物。

舉例:一個倉庫只有2個不供應食物的風車提供麵粉,那麼前2個建在它附近的面包店會正常工作,建造第3個面包店則會提示麵粉不足,即使這個倉庫裡面還有麵粉(會保留給舊客戶)。要改變這個情況,只有多建立磨坊或者給磨坊提供食物,使他們產出更多的麵粉送到倉庫來。

三、倉庫間運輸注意點

如上面所說,倉庫要保障屬於自己的建築的供給。如果沒有所需物資。必須去其他倉庫取。 但是倉庫工人就4個。如果你在一個倉庫邊建立了很多不同的建築,再分發不同的食物,那麼除非這個倉庫就是開始的主倉庫,否則你會讓這個倉庫的工人忙死,不 停地四處奔波取得物資。而且有一點,倉庫間運輸,是沒有最低保障限制的,但是運輸過程中的物資,是不參與生產流通的。

舉例:A倉庫與B倉庫各有一個面包店所屬,但是麵粉只送往A倉庫,那麼B倉庫的工人就 會去A倉庫取。那麼你就要保證A、B2個倉庫裡面都有最少1個麵粉,在途中運送的工人也有1個麵粉,兩個面包店才能正常工作。否則B倉庫的工人把A倉庫的 麵粉拿光了,A面包店就會停業,反之,B倉沒麵粉,B店也好不到哪裡去。結果兩個店舖都不能達到最大化生產。

四、 消耗。

工人物語7的所有生產建築,不論你供給什麼食物,有且只有1個工人在勞動。從去倉庫拿材料到生產再到把成品運載到倉庫,都是他一個人負責。在每次去倉庫拿原料的時候,他就會順手把食物拿回家。

如果缺少原料或者食物,他就會在家發呆。也就是說,如果我們要生產不停,必須能保證原 料和食物都在專屬倉庫有充足的供給。以食物生產舉個例子,一個平民的居所,建立了3個麵包店,不給食物的話,就會消耗3麵粉產出3麵包。提供一般的食物。 那麼他們每次消耗就是3麵粉,3麵包,生產6麵包!也就是說除非提供肉(高級食物),否則你提供食物與否,生產多餘的麵包一樣都是3個!

這代表什麼,就是說,我們不能再像工6那樣,保證每個人都有飯吃。。。。。。只有關鍵 的單位才能得到食物,例如做香腸的,做武器的。除非是後期,富裕之後你用金幣去買食物。除此之外,你每一個選擇提供食物的房子都必須精打細算,會不會造成 食物消耗過大,直接影響整個城市的生產鏈。最常見的就是,因為給礦工和漁獵工都提供一般食物,然後導致磨坊缺食物或者麵包店缺食物,後面直接導致整個城市 都缺一般食物。磨坊和麵包店這2個是城市食物鏈最大的影響因素,一定要注意。

這也是工人物語7一個重要的觀念,資源的平衡。

五、總結。

1、倉庫不要多建,尤其是在城市裡面,不要讓太多原料在路上跑。

2、同類生產建築最好集中放置,儘量讓他們同屬一個倉庫,減少工人搬運的時間:這樣同樣的原料,就不需要搬到別的地方,記住原料的搬運是很耗時的。

3、生產建築要有多餘,特別是食物建築,原料建築與消耗建築的比例,決不能是1:1。更不能看見倉庫有點存糧就大開倉庫,入不敷出的結果最後就是整個城市崩潰:這是因為原料運送需要時間,如果因為運送不及,會造成工廠停工等食物,時間就白白浪費了。

4、有些建築是值得提供一般食物的,如獵人、礦工、磨坊、牧場;有些則最好提供肉,例如所有貴族住宅的工廠,至於麵包店,一般不要給食物為好(能做不能吃。。。。)。麵包店是這樣子的,因為給一般食物時,生產是x2,但同時要消耗1個食物,這樣麵包店的效率等於沒提供食物,如果提供高級食物,生產x3,但會消耗1個高級食物,值不值得就看狀況,但一般而言是不值得的,多建一些麵包店比較實在。

工人物語7 第7關 心得

最近迷上了工人物語7,玩了幾天,遇到不少困難,所以在這裡紀錄一下心得,以免將來忘記。

在這裡先說明一下,過關的方式有很多種,這裡只是寫下我的方式,將來有空時,也許會試著發展別的過關方試。

第1-5關等於是教學,所以跟著指示做,應該沒什麼問題。

第6關:

  是騎兵剛出現的一關,我失敗了很多次,總是敗在資源不夠平衡,不是石頭不夠就是木板不夠。最後的方式是,一開始就可以馬上出兵攻地盤,然後先產生木板,再攻第2塊地,再產生木板,然後才開始發展。

  這一關是練習資源平衡的機會,要好好體會資源如何平衡,才不會最後急著蓋建築物卻沒有木板。

第7關:

   這一關很慘,一開始不知道城堡可以升級,一下子就被幹掉了,最後上網找資料,終於過關。

   一開始除了木板和石塊要馬上建之外,就是快速建兵營,在兵營買兵便宜很多,建兵營後,就買兵。另外,一開始時一定要保持3個兵,這樣那個誰的姊姊才會往下攻,如果一開始就在酒館(Tavern)中買2個兵(錢只夠這樣),敵人就會先打上邊的地,最後攻到你門前右邊的地時,就會有一大堆兵。所以要先保持3個兵,這樣敵人就會直攻你右邊的地。當敵人在打城塔時,就趕快補兵。

    等到敵人一攻佔城堡,城塔會被破壞,所以馬上可以攻打,此時,敵人應該只是剩4或5個兵,你的兵力應該可以輕易擊敗敵人。可以算準時間,城塔一壞(敵人佔城時)時,我方軍隊就到,這是最好的。打下主城右方的地,除了一邊建設,一定要馬上修護並升級城堡。

    城堡的升級很重要,在網路上有說,當主城升級到石頭圍牆時,敵人就不會攻打主城了。但是主城前右邊的地(前面佔領的),雖然升級到石塔,最後敵人也還是會攻的,所以記得要適當兵力防守。好像只要不要低於敵人太多,敵人就不會攻打了。當然,如果在敵人攻打前,就得到勝力點數是最好,但我是撐很久(我喜歡建設)。同樣的資源的平衡很重要,我這關還是苦於食物一直不夠的狀態,下關要好好的平衡一下。

    另外,衣服很重要的,因為衣服可以換錢和換石頭,大量的建設是需要大量的石頭,所以製衣廠和製布廠是值得投入高級食物的。

2011年8月24日 星期三

推薦的「食譜」網站

最近正在學習如何分享學習心得,不小心逛到一個Blog,叫作Mkyoung.com。

裡面介紹了許多的教學,例如 Java I/O、 Spring MVC、Hibernate等等。

對我這樣的初學者而言,是個很有用的網站。

有需的人可以去逛逛。當然,那個部落格也是我的典範。

至於為什麼叫「食譜」?猜一下吧。

 

2011年8月21日 星期日

最小的 NetBeans 應用程式?

在官方教學文件 NetBeans Platform Runtime Container Tutorial 這篇文章中提到,NetBeans RCP最基本的「容器」包含5個模組(Module),而6.9版後,把Lookup API再分離出來。
所以一直想試試7.0.1版後,最小的應用程式為何?所以建了一個應用程式,就稱為MinAPP,然後在Library中,先去除所有的模組的相依性(Dependency),先選一個Bootstrap模組。
min01
再按下過 Resolve 按鈕,IDE「只」選了4個模組,分別是Bootstrap、Lookup API、Module System API、Utilities API等,然後試著執行,真的可以執行,如同預期的,只看到啟動畫面,然後就什麼都沒有了。
比較奇怪的是,不需要Startup和Filesystem API這兩個模組,這就留待後面再研究了。