當使用 synchronized 關鍵字 來保護代碼塊時,必須把對象引用做爲 傳入參數。java
一般狀況下,使用 this 關鍵字來引用執行方法所屬的對象,也能夠使用其餘的對象對其進行引用。通常來講,這些對象就是爲了這個目的而建立的。ide
例如,在類中有兩個非依賴屬性,它們被多個線程共享,你必須同步每個變量的訪問,可是同一時刻 只容許一個線程訪問一個屬性變量,其餘的某個線程訪問另一個屬性變量。測試
示例: 模擬實現 電影院售票場景,有2個 屏幕 和 2個售票處的電影院,一個售票處賣出的一張票,只能用於其中的一個電影院,不能同時用於2個電影院,所以每一個電影院的剩餘票數是獨立的屬性。this
/** * 使用非依賴屬性實現同步 * 電影院 * 模擬電影院售票情景 */ public class Cinema { private long vacanciesCinema1; // 電影院1 的票 private long vacanciesCinema2; // 電影院2 的票 // 2個對象屬性 private final Object controlCinema1, controlCinema2; public Cinema(){ controlCinema1 = new Object(); controlCinema2 = new Object(); vacanciesCinema1 = 20; vacanciesCinema2 = 20; } // 第一個電影院賣票 -> 使用 controlCinema1對象來控制同步代碼塊的訪問. public boolean sellTickets1(int num){ synchronized (controlCinema1) { if(vacanciesCinema1 < num){ return false; } vacanciesCinema1 -= num; return true; } } // 第二個電影院賣票 -> 使用 controlCinema2對象來控制同步代碼塊的訪問. public boolean sellTickets2(int num){ synchronized (controlCinema2) { if(vacanciesCinema2 < num){ return false; } vacanciesCinema2 -= num; return true; } } //第一個電影院退票 public boolean returnTickets1(int num){ synchronized (controlCinema1) { vacanciesCinema1 += num; return true; } } //第二個電影院退票 public boolean returnTickets2(int num){ synchronized (controlCinema2) { vacanciesCinema2 += num; return true; } } public long getVacanciesCinema1() { return vacanciesCinema1; } public long getVacanciesCinema2() { return vacanciesCinema2; } }
/*** * 售票處1 */ public class TicketOffice1 implements Runnable{ private Cinema cinema; public TicketOffice1(Cinema cinema) { this.cinema = cinema; } public void run() { cinema.sellTickets1(2); cinema.sellTickets1(1); cinema.sellTickets2(3); cinema.sellTickets2(2); cinema.returnTickets1(1); cinema.returnTickets2(2); } }
/*** * 售票處2 */ public class TicketOffice2 implements Runnable{ private Cinema cinema; public TicketOffice2(Cinema cinema){ this.cinema = cinema; } @Override public void run() { cinema.sellTickets1(1); cinema.sellTickets2(2); cinema.sellTickets1(5); cinema.sellTickets1(3); cinema.sellTickets2(4); cinema.returnTickets1(2); cinema.returnTickets2(1); } }
/** * 測試 */ public class CinemaTest { public static void main(String[] args) { Cinema cinema = new Cinema(); TicketOffice1 ticketOffice1 = new TicketOffice1(cinema); TicketOffice2 ticketOffice2 = new TicketOffice2(cinema); Thread thread1 = new Thread(ticketOffice1); Thread thread2 = new Thread(ticketOffice2); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println("電影院1 剩餘:" + cinema.getVacanciesCinema1()); System.err.println("電影院2 剩餘:" + cinema.getVacanciesCinema2()); } } //console結果: 電影院1 剩餘:11 電影院2 剩餘:12