java進階:15.2 多線程 - synchronized、線程安全類


如果一個類的對象在多線程程序中沒有導致競爭狀態,則稱這樣的類爲線程安全的( thread-safe) 。

多線程的同步問題指的是多個線程同時修改一個數據的時候,可能導致的問題多線程的問題,又叫 Concurrency 問題

1. 線程同步概念

當兩個任務以一種會引起衝突的方式訪問一個公共資源時,會引起競爭

package Thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AccountWithoutSync {

	private static Account account =  new Account();
	
	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		
		for(int i = 0; i < 100; i++)  //創建100 個在線程池executor 中執行的線程
			executor.execute(new AddPennyTask());
		
		executor.shutdown();
		while(!executor.isTerminated()) {  //測試線程是否終止
		}
		System.out.println("what is balance?" + account.getBalance());
	}
	
	
	private static class AddPennyTask implements Runnable{
		public void run() {
			account.deposit(1);
		}
	}
	

	private static class Account{
		private int balance = 0;
	
		public int getBalance() {
			return balance;
		}
	
		public void deposit(int amount) {
			int newBalance = balance + amount;
			
	
			try {
				Thread.sleep(5);
			}
			catch(InterruptedException ex) {
			}
	
			balance = newBalance;
		}	
	}
}

 

2. synchronized

爲避免競爭狀態,應該防止多個線程同時進入程序的某一特定部分,程序中的這部分稱爲臨界區( critical regioD) 。

可以使用關鍵字synchronized 來同步方法,以便一次只有一個線程可以訪問這個方法。

對於競爭衝突問題,有幾種辦法可以解決。

  1. 一種辦法是通過在deposit 方法中添加關鍵宇synchronized ,使Account 類成爲線程安全的.public synchronized void deposit(int amount)

  2. 一個同步方法在執行之前需要 加鎖( 15.3內容 )

Object someObject =new Object();
synchronized (someObject){
        //此處的代碼只有佔有了someObject後纔可以執行
}

synchronized 表示當前線程獨佔對象 someObject

當前線程獨佔了對象someObject,如果有其他線程試圖佔有對象someObject,就會等待,直到當前線程釋放對someObject的佔用。

someObject 又叫同步對象,所有的對象,都可以作爲同步對象。爲了達到同步的效果,必須使用同一個同步對象

釋放同步對象的方式: synchronized 塊自然結束,或者有異常拋出

 
 

3. 同步語句

當執行方法中某一個代碼塊時,同步語句不僅可用於對 this 對象加鎖,而且可用於對任何對象加鎖。這個代碼塊稱爲同步塊。

 synchronized (expr) {
        statements;
  }

表達式expr 求值結果必須是一個對象的引用。如果對象已經被另一個線程鎖定,則在
解鎖之前,該線程將被阻塞。當獲准對一個對象加鎖時,該線程執行同步塊中的語句,然後解除給對象所加的鎖。
 
 

4. 線程安全類

如果一個類,其方法都是有synchronized修飾的,那麼該類就叫做線程安全的類

同一時間,只有一個線程能夠進入 這種類的一個實例 的去修改數據,進而保證了這個實例中的數據的安全(不會同時被多線程修改而變成髒數據)

比如StringBuffer和StringBuilder的區別
StringBuffer的方法都是有synchronized修飾的,StringBuffer就叫做線程安全的類
而StringBuilder就不是線程安全的類
 
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章