當使用synchronized關鍵字去同步一個代碼塊時,咱們必須傳遞一個引用,一般狀況下能夠使用this關鍵字做爲參數,可是也能夠使用其餘的引用;例如在一個類中有兩個屬性,當多個線程共享這個類時,必須同步這兩個屬性;在同一時間,一個線程訪問其中一個屬性,另一個線程訪問另一個屬性,這樣也是沒問題的;java
在下面的例子中模擬一個電影院,這個電影院有兩個熒幕和兩個獨立的售票窗口,每一個售票窗口對應一個熒幕;相互不影響;因此它們餘票數目也是相互獨立的;ide
1.建立一個cinema,並分別實現兩套相互獨立的售票和返票的方法this
public 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; } // It uses the controlCinema1 object to control the access to // the synchronized block of code public boolean sellTickets1 (int number) { synchronized (controlCinema1) { if (number<vacanciesCinema1) { vacanciesCinema1-=number; return true; } else { return false; } } } // It uses the controlCinema2 object to control the access to // the synchronized block of code public boolean sellTickets2 (int number){ synchronized (controlCinema2) { if (number<vacanciesCinema2) { vacanciesCinema2-=number; return true; } else { return false; } } } // It uses the controlCinema1 object to control the access to // the synchronized block of code public boolean returnTickets1 (int number) { synchronized (controlCinema1) { vacanciesCinema1+=number; return true; } } // It uses the controlCinema2 object to control the access to // the synchronized block of code public boolean returnTickets2 (int number) { synchronized (controlCinema2) { vacanciesCinema2+=number; return true; } } public long getVacanciesCinema1() { return vacanciesCinema1; } public long getVacanciesCinema2() { return vacanciesCinema2; } }2.建立兩個售票窗
(1)spa
public 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); cinema.sellTickets2(2); } }(2)
public 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); } }3.Main方法
public class Main { 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(); thread2.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.getVacanciesCinema2()); } }
Room 1 Vacancies: 5
Room 2 Vacancies: 6
線程
JVM確保一個線程只能訪問其中一個被同步的同一個對象的代碼塊(這裏是說的是對象,而不是類),在這個例子中,vacanciesCinema1,vacanciesCinema2這兩個對象控制訪問對應的屬性,因此每次只能有一個線程修改一個屬性;兩個線程也能夠同時運行,分別修改對應的屬性;code