在同步的類裡安排獨立屬性
當你使用synchronized關鍵字來保護代碼塊時,你必須通過一個對象的引用作為參數。通常,你将會使用this關鍵字來引用執行該方法的對象,但是你也可以使用其他對象引用。通常情況下,這些對象被建立隻有這個目的。比如,你在一個類中有被多個線程共享的兩個獨立屬性。你必須同步通路每個變量,如果有一個線程通路一個屬性和另一個線程在同一時刻通路另一個屬性,這是沒有問題的。
在這個指南中,你将學習如何解決這種情況的一個例子,程式設計模拟一家電影院有兩個螢幕和兩個售票處。當一個售票處出售門票,它們用于兩個電影院的其中一個,但不能用于兩個,是以在每個電影院的免費席位的數量是獨立的屬性。
準備工作
這個指南的例子使用eclipse ide實作。如果你使用eclipse或其他ide,如netbeans,打開它并建立一個新的java項目。
如何做…
按以下步驟來實作的這個例子:
1.建立一個cinema類,添加兩個long類型的屬性,命名為vacanciescinema1和vacanciescinema2。
2.給cinema類添加兩個額外的object屬性,命名為controlcinema1和controlcinema2。
3.實作cinema類的構造方法,初始化所有屬性。
4.實作selltickets1()方法,當第一個電影院出售一些門票将調用它。使用controlcinema1對象來控制通路synchronized的代碼塊。
5.實作selltickets2()方法,當第二個電影院出售一些門票将調用它。使用controlcinema2對象來控制通路synchronized的代碼塊。
6.實作returntickets1()方法,當第一個電影院被退回一些票時将調用它。使用controlcinema1對象來控制通路synchronized的代碼塊。
7.實作returntickets2()方法,當第二個電影院被退回一些票時将調用它。使用controlcinema2對象來控制通路synchronized的代碼塊。
8.實作其他兩個方法,用來傳回每個電影院空缺位置的數量。
9.實作ticketoffice1類,并指定它實作runnable接口。
10.聲明一個cinema對象,并實作該類(類ticketoffice1)的構造器用來初始化這個對象。
11.實作run()方法,用來模拟在兩個電影院的一些操作。
12.實作ticketoffice2類,并指定它實作runnable接口。
13.聲明一個cinema對象,并實作該類(類ticketoffice2)的構造器用來初始化這個對象。
14.實作run()方法,用來模拟在兩個電影院的一些操作。
15.通過建立類名為main,且包括main()方法來實作這個示例的主類。
16.聲明和建立一個cinema對象。
17.建立一個ticketoffice1對象,并且用線程來運作它。
18.建立一個ticketoffice2對象,并且用線程來運作它。
19.啟動這兩個線程。
20.等待線程執行完成。
21.兩個電影院的空缺數寫入控制台。
它是如何工作的…
當你使用synchronized關鍵字來保護代碼塊,你使用一個對象作為參數。jvm可以保證隻有一個線程可以通路那個對象保護所有的代碼塊(請注意,我們總是談論的對象,而不是類)。
注釋:在這個示例中,我們用一個對象來控制vacanciescinema1屬性的通路。是以,在任意時刻,隻有一個線程能修改該屬性。用另一個對象來控制 vacanciescinema2屬性的通路。是以,在任意時刻,隻有一個線程能修改這個屬性。但是可能有兩個線程同時運作,一個修改 vacancescinema1屬性而另一個修改vacanciescinema2屬性。
當你運作這個示例,你可以看到每個電影院的空缺數量的最後的結果總是預期的。在以下截圖中,你可以看到應用程式的執行結果:
不止這些…
synchronize關鍵字還有其他重要用法,請見其他指南中解釋這個關鍵字使用的參見部分。
參見
在第2章,基本線程同步中在同步代碼中使用條件的指南。