1. 程式人生 > >執行緒安全-鎖機制 synchronized用法同步方法

執行緒安全-鎖機制 synchronized用法同步方法

一個簡單的例子,10個人搶8張票,結果肯定是有2個人搶不到票的

public class Ticket {
	private static CountDownLatch  ctl =new  CountDownLatch(1);
	private ReentrantLock rentLock=new ReentrantLock();
	
	Integer stock=8;//總票數
	
	public  void reduce(int num){
		if((stock-num)>=0){
			
			try {
				ctl.await();//模擬併發場景,相當於所用執行緒同時到達才會執行
			} catch (Exception e) {
				e.printStackTrace();
			}
			stock-=num;
			System.out.println(Thread.currentThread().getName()+
				"成功賣出:"+num+"張,庫存剩餘:"+stock+"張");
		}else {
			System.out.println(Thread.currentThread().getName()+
					"失敗,庫存不足:"+num+"張,庫存剩餘:"+stock+"張");
		}
	}
	

	
	public static void main(String[] args) throws InterruptedException {
		final Ticket ticket=new Ticket();
		
		for (int i = 0; i <10; i++) {
			new Thread(new Runnable() {
				public void run() {
					ticket.reduce(1); #只有10個執行緒同時開啟時,才會執行該方法,因為reduce方法中呼叫了ctl.await方法
					//ticket.reduceByLock(1);
				}
			}).start();;
		}
		Thread.sleep(1000);
		ctl.countDown();  //啟動一個執行緒,計數器減一
	}
	
}

執行結果: 在這裡插入圖片描述 出現的負數,這就是執行緒安全引起的,只要把Ticket 中的reduce 方法加上synchronized 修飾,就可以解決這個問題

一 同步方法 方法加用 synchronized 修飾

public synchronized void reduce(int num){
		if((stock-num)>=0){
			
			try {
				ctl.await();//模擬併發場景,相當於所用執行緒同時到達才會執行
			} catch (Exception e) {
				e.printStackTrace();
			}
			stock-=num;
			System.out.println(Thread.currentThread().getName()+
				"成功賣出:"+num+"張,庫存剩餘:"+stock+"張");
		}else {
			System.out.println(Thread.currentThread().getName()+
					"失敗,庫存不足:"+num+"張,庫存剩餘:"+stock+"張");
		}
	}

再次執行結果: 在這裡插入圖片描述

為什麼呢,因為加了synchronized 關鍵字後,會保證每次只會用一個執行緒去呼叫reduce這個方法,當一個執行緒1在執行這個方法的時候,會獲得鎖,其他執行緒阻塞等待,執行緒1執行完之後,釋放鎖,其他執行緒競爭鎖。得到鎖的執行緒執行reduce方法,其他執行緒阻塞等待,以此類推,直到10個執行緒都執行完

加在方法上的鎖(也叫同步方法),鎖的都是物件,例子中執行時鎖的就是這個 ticket 物件(也就是呼叫reduce這個方法的物件) 在這裡插入圖片描述

同步方法的缺點:因為鎖在方法上,導致了鎖的範圍過大,會使單個執行緒序列執行時間變長,其他執行緒等待時間變長;影響系統性能