1. 程式人生 > >自學java多執行緒(二)------執行緒的同步

自學java多執行緒(二)------執行緒的同步

1.執行緒同步方式synchronised

為什麼要執行緒同步,舉個簡單的例子,你的銀行賬戶一共有3000塊錢,你的手裡有這3000塊的存摺,你的妻子手裡有這3000塊的銀行卡,你拿著存摺到銀行取2000塊錢,與此同時,你的妻子拿著銀行卡到取款機取2000塊,你們兩個人同時訪問了同一個銀行賬戶,訪問的時候,餘額都是3000塊,當進行取錢操作的時候,系統會判斷你的賬戶裡的錢足夠你和你妻子取出的數目,這樣,賬戶就會同時給你和你妻子一人2000塊,然後賬戶餘額剩下1000,顯然這對銀行來說是虧損,為了避免這個情況,就需要執行緒同步。當你取錢的時候,訪問這個賬戶的餘額的同時給這個賬戶加上一把鎖,在此期間其他人無法訪問這個賬戶,直到這個鎖失效,這樣就達到了執行緒同步的目的。

看下面例子:

package Thread;

public class TestSync implements Runnable {
	Timer timer = new Timer();
	
	public static void main(String[] args) {
		TestSync test = new TestSync();
		Thread thread1 = new Thread(test);
		Thread thread2 = new Thread(test);
		
		thread1.setName("t1");
		thread2.setName("t2");
		
		thread1.start();
		thread2.start();
	}

	@Override
	public void run() {
		timer.addNum(Thread.currentThread().getName());
	}
	
}

class Timer{
	private int num = 0;
	public void addNum(String name){
		num++;
		try{
			Thread.sleep(1);
		}catch(Exception e){
			
		}
		System.out.println(name+",你是第"+num+"個訪問timer的執行緒");
	}
}

輸出結果:    t1,你是第2個訪問timer的執行緒

                    t2,你是第2個訪問timer的執行緒

很明顯這不是我們想要的結果,期待的結果應該是:t1,你是第1個訪問timer的執行緒,t2,你是第2個訪問timer的執行緒。為什麼會出現這種情況呢?當t1執行addNum的時候,num 變成了1,然後程式睡眠了1毫秒,此時t2訪問addNum模組,num再次+1變為2,當t1繼續執行的時候,num就變成了2.如果想要期待的輸出結果,就需要執行緒同步,在上面的addNum方法上加一把鎖。讓addNum方法在同一時間只能有一個執行緒訪問。程式碼如下

class Timer{
	private int num = 0;
	public void addNum(String name){
		synchronized (this) {
			num++;
			try{
				Thread.sleep(1);
			}catch(Exception e){
				
			}
			System.out.println(name+",你是第"+num+"個訪問timer的執行緒");
		}
	}
}

當t1執行addNum方法時候,synchronized給當前物件上了鎖,其他執行緒只能等到t1訪問結束,才能訪問addNum方法。

輸出結果:    t1,你是第1個訪問timer的執行緒

                    t2,你是第2個訪問timer的執行緒

2.死鎖

簡單的來說就是兩個擁有鎖的資源互相訪問。形成了死鎖。看例子程式

package Thread;

public class TestDeadLock implements Runnable{
	public int flag = 1;
	static Object o1 = new Object(),o2 = new Object();
	@Override
	public void run() {
		System.out.println("flag=="+flag);
		if(flag == 1){
			synchronized(o1){
				try{
					Thread.sleep(500);
				}catch(Exception e){}
				synchronized(o2){
					System.out.println("1");
				}
			}
		}
		if(flag == 0){
			synchronized(o2){
				try{
					Thread.sleep(500);
				}catch(Exception e){}
				synchronized(o1){
					System.out.println("0");
				}
			}
		}
	}
	public static void main(String[] args) {
		TestDeadLock test1 = new TestDeadLock();
		TestDeadLock test2 = new TestDeadLock();
		test1.flag = 1;
		test2.flag = 0;
		Thread t1 = new Thread(test1);
		Thread t2 = new Thread(test2);
		
		t1.start();
		t2.start();
	}

}
上面程式中兩個執行緒就形成了死鎖,解決的辦法是同步的顆粒度粗一點,不要給物件加鎖,最好給程式碼塊加鎖。至於其他的解決方法也很多,就介紹了。