當使用synchronized關鍵字來保護代碼塊時,必須把對象引用做爲傳入參數。一般狀況下,使用this關鍵字來引用執行方法所屬的對象,也可使用其餘的對象對其進行引用。通常來講,這些對象就是爲這個目的而建立的。例如,在類中有兩個非依賴屬性,它們被多個線程共享,你必須同步每個變量的訪問,可是同一時刻只容許一個線程訪問一個屬性變量,其餘某個線程訪問另外一個屬性變量。java
這裏咱們演示電影院售票場景。這個範例模擬了有兩個屏幕和兩個售票處的電影院。一個集票處賣出的一張票,只能用於其中一個屏幕,不能同時用於兩個屏幕,所以每一個電影院的剩餘票數是獨立的屬性。ide
示例:this
package concurrency; public class Main9 { public static void main(String[] args) { Cinema cinema = new Cinema(); TicketOffice1 ticketOffice1 = new TicketOffice1(cinema); Thread thread1 = new Thread(ticketOffice1,"TicketOffice1"); TicketOffice2 ticketOffice2 = new TicketOffice2(cinema); Thread thread2 = new Thread(ticketOffice2,"TicketOffice2"); thread1.start(); thread2.start(); try { //等待這兩個線程結束!! thread1.join(); thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Room 1 Vacancies: %d\n", cinema.getVacanciesCinema1()); System.out.printf("Room 2 Vacancies: %d\n", cinema.getVacanciesCinerna2()); } } //電影院類 class Cinema{ private long vacanciesCinema1; private long vacanciesCinema2; private final Object controlCinema1,controlCinema2; public Cinema(){ controlCinema1 = new Object(); controlCinema2 = new Object(); vacanciesCinema1 = 20; vacanciesCinema2 = 20; } public boolean sellTickets1(int number) { synchronized (controlCinema1) { if(number < vacanciesCinema1){ vacanciesCinema1 -= number; return true; }else{ return false; } } } public boolean sellTickets2(int number) { synchronized (controlCinema2) { if(number < vacanciesCinema2){ vacanciesCinema2 -= number; return true; }else{ return false; } } } public boolean returnTickets1(int number){ synchronized (controlCinema1) { vacanciesCinema1 += number; return true; } } public boolean returnTickets2(int number){ synchronized (controlCinema2) { vacanciesCinema2 += number; return true; } } public long getVacanciesCinema1(){ return vacanciesCinema1; } public long getVacanciesCinerna2(){ return vacanciesCinema2; } } //售票處1 class TicketOffice1 implements Runnable{ private Cinema cinema; public TicketOffice1(Cinema cinema) { this.cinema = cinema; } //模擬對電影院的操做 @Override public void run() { cinema.sellTickets1(3); cinema.sellTickets1(2); cinema.sellTickets2(2); cinema.returnTickets1(3); cinema.sellTickets1(5); cinema.sellTickets2(2); cinema.sellTickets2(2); } } //售票處2 class TicketOffice2 implements Runnable{ private Cinema cinema; public TicketOffice2(Cinema cinema) { this.cinema = cinema; } //模擬對電影院操做 @Override public void run() { cinema.sellTickets2(2); cinema.sellTickets2(4); cinema.sellTickets1(2); cinema.sellTickets1(1); cinema.returnTickets2(2); cinema.sellTickets1(3); cinema.sellTickets2(2); cinema.sellTickets1(2); } }
用synchronized關鍵字保護代碼塊時,咱們使用對象做爲它的傳入參數。JVM保證同一時間只有一個線程可以訪問這個對象保護的代碼保護塊(注意:咱們一直談論的是對象,不是類)。spa
備註:這個例子使用了一個對象來控制對vacanciesCinema1屬性的訪問,因此同一時間只有一個線程可以修改這個屬性; 使用了另外一個對象來控制vacanciesCinema2屬性的訪問,因此同一時間只有一個線程可以修改這個屬性。可是,這個例子容許同時運行兩個線程:一個修改vacancesCinema1屬性,另外一個修改vacanciesCinema2屬性。
線程