多線程併發之對synchronized和Lock的簡單使用

比如有三個線程thread-0,  thread-1,  thread-3

三個線程同時在執行一個帶鎖的方法時,如果thread-0先獲得了鎖,那麼其它二個線程就只能外面等着,直到thread-0把鎖給釋放了,這個時候就由其它線程去爭取這個鎖.

生活中的例子: 現在有三個人同時都要上廁所A,B,C . A先進入到了廁所,這個時候A就會把門給鎖了,B,C就要在外面等,直到A上完出來把門打開,這個時候B,C纔能有一個人進去,進去後也是鎖門,出來也是解鎖,然後繼續下一個人.

鎖可以解決多線程中線程安全的問題.

在android中的單例(懶漢式)

public class SingleTon {
    private static SingleTon sInstance;

    public static SingleTon getInstance() {
        if (sInstance ==null) {
            //1:
            sInstance = new SingleTon();
        }
        return sInstance;
    }
}

如果多線程調用這個getInstance的話就會有問題,下面分析一下

同樣有三個線程: thread-0, thread-1, thread-2

註釋1處: 假如thread-0執行到1處時候cpu執行器被操作系統調度給釋放了,這時thread-1進來了,發現sInstance是空的,就會執行下new代碼,最後執行完了,這個時候thread-0恢復了獲得了cpu執行權,thread-0也new出了一個,這樣這個sInstance被創建了二次,就會引發安全性問題

解決方法,加synchronized鎖住,被稱之爲隱式鎖,因爲加鎖解鎖我們都看不到,是內部自己完成的.

public class SingleTon {
    private static SingleTon sInstance;


    public synchronized static SingleTon getInstance() {
        if (sInstance ==null) {
            sInstance = new SingleTon();
        }
        return sInstance;
    }
}

synchronized使用方法

作用在靜態方法之上執行的是一個類鎖xxx.class

作用在非靜態方法之上執行的是當前的對象鎖Object object;

上面那個寫法會有性能問題,因爲每個線程都會在方法外等待,所以性能不是非常好,改進版本

public class SingleTon {
    private static SingleTon sInstance;


    public static SingleTon getInstance() {
        if (sInstance == null) {
            synchronized (SingleTon.class) {
                 if (sInstance == null) {
                     sInstance = new SingleTon();
                 }
                
            }
        }
        return sInstance;
    }
}

這二種方法執行的鎖其實是同一個鎖

這裏再多提一嘴靜態方法的synchronized和非靜態方法的區別

public class SingleTon {
    private static SingleTon sInstance;


    public synchronized static SingleTon getInstance() {
        if (sInstance ==null) {
            sInstance = new SingleTon();
        }
        return sInstance;
    }
}

public class SingleTon {
    private static SingleTon sInstance;


    public static SingleTon getInstance() {
        synchronized(SingleTon.class){
       
            if (sInstance ==null) {
                sInstance = new SingleTon();
            }
        }

        return sInstance;
    }
}

上面二個方法是等價的

public class SingleTon {
    private static SingleTon sInstance;


    public synchronized SingleTon getInstance() {
        if (sInstance ==null) {
            sInstance = new SingleTon();
        }
        return sInstance;
    }
}

public class SingleTon {
    private static SingleTon sInstance;

    public SingleTon getInstance() {
        synchronized(this){
       
            if (sInstance ==null) {
                sInstance = new SingleTon();
            }
        }

        return sInstance;
    }
}

這上面二個方法也是等價的

 

顯示鎖 Lock: 我們程序員可以自己控制

在下面這個demo中可以發現在二個線程都執行add這個方法的時候會出現線程安全問題,解決方法有二種

1:在方法上加個synchronized,第二種方法使用Lock這個來操作加鎖解鎖,  synchronized天生是可重入鎖

public class LockDemo {
    private int mCount = 0;
    private Lock mLock = new ReentrantLock();//這是一個可重入鎖

    public void add() {//有問題
        mCount++;
    }
    
    public void add() {//沒問題
        mLock.lock();//自己加鎖
        mCount++;//如果這裏發生異常,下面就不會解鎖,就會導致所有線程都進不來
        mLock.unlock();//自己解鎖
    }
    public void add() {//沒問題
        try {
            mLock.lock();
            mCount++;
        }finally {
            mLock.unlock();
        }
      
    }

    public synchronized void add() {//沒問題
        mCount++;
    }

    private static class MyThread extends Thread {
        LockDemo mLockDemo;

        public MyThread(LockDemo lockDemo) {
            mLockDemo = lockDemo;
        }

        @Override
        public void run() {
            super.run();
            for (int i = 0; i < 10000; i++) {
                mLockDemo.add();
            }
        }
    }

    public static void main(String[] args) {

        LockDemo lockDemo = new LockDemo();
        new MyThread(lockDemo).start();
        new MyThread(lockDemo).start();
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("count: " + lockDemo.mCount);
    }

}

 

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