1. 程式人生 > >synchronized 和 lock 基本使用以及死鎖分析

synchronized 和 lock 基本使用以及死鎖分析

1.未加鎖

多執行緒程式未加鎖可能產生安全問題

執行緒未加鎖可能造成資料重複訪問

如下程式


public class SellTickets implements Runnable{
    private int ticketNumber = 100;
    @Override
    public void run() {
        while(true){
            if(ticketNumber > 0){
                System.out.println(Thread.currentThread().getName()+"正在出售第"
+ ticketNumber-- +"張票"); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { SellTickets seller = new SellTickets(); Thread seller1 = new
Thread(seller,"售票員1"); Thread seller2 = new Thread(seller,"售票員2"); Thread seller3 = new Thread(seller,"售票員3"); seller1.start(); seller2.start(); seller3.start(); } }

Console

error

2.使用synchronized加鎖

synchronized特性:

一 : 採用synchronized修飾符實現的同步機制叫做互斥鎖機制,它所獲得的鎖叫做互斥鎖。每個物件的鎖只能分配給一個執行緒,因此叫做互斥鎖
二 :類的每個例項都有自己的物件級別鎖。當一個執行緒訪問例項物件中的synchronized同步程式碼塊或同步方法時,該執行緒便獲取了該例項的物件級別鎖,其他執行緒這時如果要訪問synchronized同步程式碼塊或同步方法,便需要阻塞等待,直到前面的執行緒從同步程式碼塊或方法中退出,釋放掉了該物件級別鎖
三 :訪問同一個類的不同例項物件中的同步程式碼塊,不存在阻塞等待獲取物件鎖的問題,因為它們獲取的是各自例項的物件級別鎖,相互之間沒有影響。

為synchronized指定程式碼塊加鎖(該程式碼塊一個執行緒訪問時,其他執行緒無法同時訪問此塊程式碼)

synchronized ((同步物件一般用)this) {
            //指定程式碼塊
            //鎖物件可以是任意物件(但須確保為同一物件才能保證資料加鎖)
        }

synchronized修飾方法,則該方法內所有程式碼加鎖
若synchronized需加鎖為靜態方法一般採用則使用類名.class作為引數

3.使用Lock加鎖

lock特徵:
Lock實現提供比使用synchronized方法和語句可以獲得的更廣泛的鎖定操作。 它們允許更靈活的結構化,可能具有完全不同的屬性,並且可以支援多個相關聯的物件Condition 。
所有已知實現類:
ReentrantLock( 重入鎖), ReentrantReadWriteLock.ReadLock (讀鎖), ReentrantReadWriteLock.WriteLock (寫鎖)

本文將使用ReentrantLock實現類來為執行緒加鎖,需要注意,鎖物件解鎖需要在finally語句塊中,

ReentrantLock lock = new ReentrantLock();
        while(true){
            try{
                lock.lock();
                if(ticketNumber > 0){
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+ ticketNumber-- +"張票");
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally{
                lock.unlock();
            }
        }

4.死鎖問題

如果出現了同步巢狀,就容易產生死鎖問題
是指兩個或者兩個以上的執行緒在執行的過程中,因爭奪資源產生的一種互相等待現象
可以理解為A執行緒訪問某B執行緒正在訪問的物件過程中,B執行緒同時訪問A所訪問的物件,相互加鎖,無法正常執行
同步程式碼塊的巢狀案例


public class DieLockDemo extends Thread{
    //建立兩把鎖物件
    public static final Object obj1 = new Object();
    public static final Object obj2 = new Object();
    private boolean flag = false;
    public DieLockDemo(String name ,boolean flag) {
        super(name);
        this.flag = flag;
    }

    @Override
    public void run() {
        while(true){
            if(flag){
                synchronized (obj1) {
                    System.out.println(getName()+" use obj1");
                    synchronized (obj2) {
                        System.out.println(getName()+" use obj2");
                    }
                }
            } else {
                synchronized (obj2) {
                    System.out.println(getName()+" use obj1");
                    synchronized (obj1) {
                        System.out.println(getName()+" use obj2");
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        DieLockDemo d1 = new DieLockDemo("小王", true);
        DieLockDemo d2 = new DieLockDemo("小強", false);
        d1.start();
        d2.start();

    }
}