天天看點

線程同步工具(二)控制并發通路多個資源

在并發通路資源的控制中,你學習了信号量(semaphores)的基本知識。

在上個指南,你實作了使用binary semaphores的例子。那種semaphores是用來保護通路一個共享資源的,或者說一個代碼片段每次隻能被一個線程執行。但是semaphores也可以用來保護多個資源的副本,也就是說當你有一個代碼片段每次可以被多個線程執行。

在這個指南中,你将學習怎樣使用semaphore來保護多個資源副本。你将實作的例子會有一個print queue但可以在3個不同的列印機上列印檔案。

準備

指南中的例子是使用 eclipse ide 來實作的。如果你使用eclipse 或者其他的ide,例如netbeans, 打開并建立一個新的java任務。實作在控制并發通路資源裡描述的例子。

怎麼做呢<b>…</b>

按照這些步驟來實作下面的例子:

<code>01</code>

<code>//1.  如我們之前提到的,你将實作semaphores來修改print queue例子。打開printqueue類并聲明一個boolean array名為 freeprinters。這個array儲存空閑的等待列印任務的和正在列印文檔的printers。</code>

<code>02</code>

<code>private</code> <code>boolean</code> <code>freeprinters[];</code>

<code>03</code>

<code>04</code>

<code>//2.   接着,聲明一個名為lockprinters的lock對象。将要使用這個對象來保護freeprinters array的通路。</code>

<code>05</code>

<code>private</code> <code>lock lockprinters;</code>

<code>06</code>

<code>07</code>

<code>//3.   修改類的構造函數并初始化新聲明的對象們。freeprinters array 有3個元素,全部初始為真值。semaphore用3作為它的初始值。</code>

<code>08</code>

<code>public</code> <code>printqueue(){</code>

<code>09</code>

<code>10</code>

<code>semaphore=</code><code>new</code> <code>semaphore(</code><code>3</code><code>);</code>

<code>11</code>

<code>freeprinters=</code><code>new</code> <code>boolean</code><code>[</code><code>3</code><code>];</code>

<code>12</code>

<code>13</code>

<code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i&lt;</code><code>3</code><code>; i++){</code>

<code>14</code>

<code>    </code><code>freeprinters[i]=</code><code>true</code><code>;</code>

<code>15</code>

<code>}</code>

<code>16</code>

<code>lockprinters=</code><code>new</code> <code>reentrantlock();</code>

<code>17</code>

<code>18</code>

<code>19</code>

<code>//4.   修改printjob()方法。它接收一個稱為document的對象最為唯一參數。</code>

<code>20</code>

<code>public</code> <code>void</code> <code>printjob (object document){</code>

<code>21</code>

<code>22</code>

<code>//5.   首先,調用acquire()方法獲得semaphore的通路。由于此方法會抛出 interruptedexception異常,是以必須加入處理它的代碼。</code>

<code>23</code>

<code>try</code> <code>{</code>

<code>24</code>

<code>    </code><code>semaphore.acquire();</code>

<code>25</code>

<code>26</code>

<code>//6.   接着使用私有方法 getprinter()來獲得被安排列印任務的列印機的号碼。</code>

<code>27</code>

<code>int</code> <code>assignedprinter=getprinter();</code>

<code>28</code>

<code>29</code>

<code>//7.    然後, 随機等待一段時間來實作模拟列印文檔的行。</code>

<code>30</code>

<code>long</code> <code>duration=(</code><code>long</code><code>)(math.random()*</code><code>10</code><code>);</code>

<code>31</code>

<code>system.out.printf(</code><code>"%s: printqueue: printing a job in printer%d during %d seconds\n"</code><code>,thread.currentthread().getname(), assignedprinter,duration);</code>

<code>32</code>

<code>timeunit.seconds.sleep(duration);</code>

<code>33</code>

<code>34</code>

<code>//8.   最後,調用release() 方法來解放semaphore并标記列印機為空閑,通過在對應的freeprinters array引索内配置設定真值。</code>

<code>35</code>

<code>freeprinters[assignedprinter]=</code><code>true</code><code>;</code>

<code>36</code>

<code>} </code><code>catch</code> <code>(interruptedexception e) {</code>

<code>37</code>

<code>    </code><code>e.printstacktrace();</code>

<code>38</code>

<code>} </code><code>finally</code> <code>{</code>

<code>39</code>

<code>    </code><code>semaphore.release();</code>

<code>40</code>

<code>41</code>

<code>42</code>

<code>//9.  實作 getprinter() 方法。它是一個私有方法,傳回一個int值,并不接收任何參數。</code>

<code>43</code>

<code>private</code> <code>int</code> <code>getprinter() {</code>

<code>44</code>

<code>45</code>

<code>//10. 首先,聲明一個int變量來儲存printer的引索值。</code>

<code>46</code>

<code>int</code> <code>ret=-</code><code>1</code><code>;</code>

<code>47</code>

<code>48</code>

<code>//11. 然後, 獲得lockprinters對象 object的通路。</code>

<code>49</code>

<code>50</code>

<code>lockprinters.lock();</code>

<code>51</code>

<code>52</code>

<code>//12. 然後,在freeprinters array内找到第一個真值并在一個變量中儲存這個引索值。修改值為false,因為等會這個列印機就會被使用。</code>

<code>53</code>

<code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i&lt;freeprinters.length; i++) {</code>

<code>54</code>

<code>if</code> <code>(freeprinters[i]){</code>

<code>55</code>

<code>    </code><code>ret=i;</code>

<code>56</code>

<code>    </code><code>freeprinters[i]=</code><code>false</code><code>;</code>

<code>57</code>

<code>    </code><code>break</code><code>;</code>

<code>58</code>

<code>59</code>

<code>60</code>

<code>61</code>

<code>//13. 最後,解放lockprinters對象并傳回引索對象為真值。</code>

<code>62</code>

<code>} </code><code>catch</code> <code>(exception e) {</code>

<code>63</code>

<code>64</code>

<code>65</code>

<code>    </code><code>lockprinters.unlock();</code>

<code>66</code>

<code>67</code>

<code>return</code> <code>ret;</code>

<code>68</code>

<code>69</code>

<code>//14. job 和 core 類不做任何改變。</code>

它是怎麼工作的…

在例子中的printqueue類的關鍵是:semaphore對象建立的構造方法是使用3作為參數的。這個例子中,前3個調用acquire() 方法的線程會獲得臨界區的通路權,其餘的都會被阻塞 。當一個線程結束臨界區的通路并解放semaphore時,另外的線程才可能獲得通路權。

在這個臨界區,線程獲得被配置設定列印的列印機的引索值。例子的這部分讓例子更真實,而且它沒有使用任何與semaphores相關的代碼。以下的裁圖展示了這個例子的執行輸出:

線程同步工具(二)控制并發通路多個資源

每個文檔都被安排到第一個空閑的列印機列印。

更多…

the acquire(), acquireuninterruptibly(), tryacquire(),和release()方法有一個外加的包含一個int參數的版本。這個參數表示 線程想要擷取或者釋放semaphore的許可數。也可以這樣說,這個線程想要删除或者添加到semaphore的内部計數器的機關數量。在這個例子中acquire(), acquireuninterruptibly(), 和tryacquire() 方法, 如果計數器的值小于許可值,那麼線程就會被阻塞直到計數器到達或者大于許可值。

參見

<a href="http://ifeve.com/thread-synchronization-utilities-1/">第三章,線程同步應用:并發地通路資源的控制</a>

第八章,同步應用的測試:修改lock接口

<a href="http://ifeve.com/basic-thread-synchronization-7/">第二章,基本線程同步:修改lock的公平性</a>

繼續閱讀