[Java] 16.3. 同步化區塊 & 物件鎖

搭配物件鎖,讓特定區塊的程式進行同步化。

 

image/svg+xml16.3. 同步化區塊 & 物件鎖 - synchronized block & Lock class Company { int cash = 1000 ; synchronized void withdraw ( String empName, int amount){ System.out.println(empName+ " 開始提領零⽤⾦。 " ); if ( cash >= amount ){ try { Thread.sleep( 10 ); } catch ( InterruptedException e){} System.out.println(empName + " 提取了 " + amount + 元。 " ); cash=cash-amount; } System.out.println( " 剩下的零⽤⾦: " +cash); System.out.println(empName+ " 結束提領零⽤⾦。 " ); } } class Company { int cash = 1000 ; void withdraw ( String empName, int amount){ System.out.println(empName+ " 開始提領零⽤⾦。 " ); synchronized ( this ) { if ( cash >= amount ){ try { Thread.sleep( 10 ); } catch ( InterruptedException e){} System.out.println(empName + " 提取了 " + amount + 元。 " ); cash=cash-amount; } System.out.println( 剩下的零⽤⾦: " +cash); } System.out.println(empName+ " 結束提領零⽤⾦。 " ); } } class Company { int cash = 1000 ; Object lock = new Object (); void withdraw ( String empName, int amount){ System.out.println(empName+ " 開始提領零⽤⾦。 " ); synchronized ( obj ) { if ( cash >= amount ){ try { Thread.sleep( 10 ); } catch ( InterruptedException e){} System.out.println(empName + " 提取了 " + amount + 元。 " ); cash=cash-amount; } System.out.println( 剩下的零⽤⾦: " +cash); } System.out.println(empName+ " 結束提領零⽤⾦。 " ); } } class Company { int cash = 1000 ; void withdraw ( String empName, int amount){ if ( cash >= amount ){ try { Thread.sleep( 10 ); } catch ( InterruptedException e){} System.out.println(empName + " 提取了 " + amount + " 元。 " ); cash=cash-amount; } System.out.println( " 剩下的零⽤⾦: " +cash); } } class Employee extends Thread { String name; Company company; Object lock; Employee ( String name, Company company, Object lock ){ this .name = name; this .company = company; this .lock=lock; } public void run (){ for ( int i= 0 ; i< 3 ; i++) { synchronized ( lock ) { company.withdraw(name, 300 ); } } } } class Main{ public static void main( String [] args){ Company com = new Company(); Object lock = new Object (); Employee e1= new Employee ( "Jack" , com, lock ); Employee e2= new Employee ( "Eric" , com, lock ); e1.start(); e2.start(); } } 執⾏結果 Jack 提取了 300 元。 剩下的零⽤⾦: 700 Jack 提取了 300 元。 剩下的零⽤⾦: 400 Jack 提取了 300 元。 剩下的零⽤⾦: 100 剩下的零⽤⾦: 100 剩下的零⽤⾦: 100 剩下的零⽤⾦: 100 class Company { int cash = 1000 ; synchronized void withdraw ( String empName, int amount){ if ( cash >= amount ){ try { Thread.sleep( 10 ); } catch ( InterruptedException e){} System.out.println(empName + " 提取了 " + amount + " 元。 " ); cash=cash-amount; } System.out.println( " 剩下的零⽤⾦: " +cash); } } J16_3_1 Company.java 2. 不在提領⽅法( withdraw() )前加上 synchronized 關鍵字,將⽅法進⾏同步化。 J16_3_2 Company.java 1. 這是公司類別( Company ),其中有個零⽤⾦ 屬性( cash )以存放零⽤⾦,預設為 1000 3. 是否可以只同步化會影響提領零⽤⾦結果的這⼀段程式呢? 2. 不在提領⽅法( withdraw() )前加上 synchronized 關鍵字,將⽅法進⾏同步化。 1. 這是公司類別( Company ),其中有個零⽤⾦ 屬性( cash )以存放零⽤⾦,預設為 1000 3. synchronized 關鍵字可以鍵造同步化區塊,其後接的是⼀ 個⼩括號( ( ) ),⽤來指定⼀個物件,只使⽤此物件上的鎖。 4. 我們可以使⽤ this 物件上的鎖(此 this 件即是建立的公司物件),來進⾏同步化。只要 是同⼀個公司,在員⼯進⾏提顉時,皆會判斷是 否取得此 this 物件上的鎖,只有取得鎖的員⼯可 以進⾏同步化區塊中,進⾏提領的作業。 J16_3_3 Company.java 3. 不在提領⽅法( withdraw() )前加上 synchronized 關鍵字,將⽅法進⾏同步化。 1. 這是公司類別( Company ),其中有個零⽤⾦ 屬性( cash )以存放零⽤⾦,預設為 1000 2. 隨意建立⼀個物件,此物件是在 建立公司物件的同時建立的。 4. 改採⽤隨意建立的物件,作為物件鎖。只要使⽤的是同⼀個公司,就會使⽤同⼀個 物件,作為同步化區塊的物件鎖。雖然這是隨意建立的物件,但還是可以作為物件鎖。 J16_3_4 Company.java 1. 這是公司類別( Company ),其提領零⽤⾦⽅法 withdraw() )並未使⽤ synchronized 進⾏同步化。 J16_3_4 Employee.java 2. 這是員⼯類別( Employee )其繼承⾃ Thread 類別。 3. 在建立員⼯物件的同時,將作為同步化區塊的物件 鎖傳入⾄員⼯物件中,只便在進⾏同步化區塊時使⽤。 4. 改寫 run() ⽅法,並在每次提領零⽤⾦的時候, 即進⾏同步化的動作,只要員⼯們使⽤的是同⼀個物 件鎖,還是可以達到同步化提顉零⽤⾦的效果。 J16_3_4 Main.java 5. 隨意建立⼀個物件,作為物件鎖。 6. Jack Eric 員⼯皆使⽤同⼀個物件作為物件 鎖,因此在提領零⽤⾦時,會依照是否取得物件上的 鎖,⽽決定是否實際進⾏提取零⽤⾦的動作。 7. 雖然同步化區塊是建立於每位員⼯的 run() ⽅法中,但 因為物件鎖是相同的,因此還是可以達到同步化的效果。 synchronized( this ) { } 1. 這是公司類別( Company )。 2. 使⽤ synchronized 將提取零⽤⾦( withdraw() )⽅法同步化,其實在編譯時, 編譯器會將同步化的⽅式轉換為 “synchronized+ 物件鎖 的⽅式進⾏,當然,物件鎖 會以⽬前物件 this 的⽅式表⽰,⽽⽅法中的程式碼皆會被裝在這個同步化區塊中。 可以將部份程式進⾏同步化嗎? 只要在領取零⽤⾦的那⼀段程式進⾏同步化就好了! synchronized+ 物件鎖, 將領取零⽤⾦的程式區塊進⾏同步化 物件鎖可以是任何的⼀個物件, 因為每個物件都有⼀個鎖 synchronized+ 物件鎖,讓員⼯們進⾏⾃主管理, 以達到⼀次只會有⼀名員⼯領取零⽤⾦ 其實,編譯器會將加上 synchronized 的⽅法, 轉換成 synchronized+ 物件鎖的⽅式進⾏同步化 1 1

留言