1. 程式人生 > >Synchronized和執行緒安全

Synchronized和執行緒安全

執行緒安全問題

  • 什麼是執行緒安全
    多執行緒訪問時,採用了加鎖機制,當一個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能訪問知道該執行緒讀取完後,其他執行緒才可以使用出現資料不一致或者資料汙染
  • 執行緒不安全
    執行緒不安全就是不提供資料的訪問保護,有可能出現多個執行緒更改資料造成所得到的資料時髒資料(引用自http://blog.csdn.net/ghevinn/article/details/37764791/
    執行緒安全是面向同一個資源的時候才有討論價值,當時不同的資源的時候就沒有討論的價值了,比如一個銀行賬戶對其進行檢視餘額和存入金額的操作的時候就需要討論執行緒安全的問題

Synchronized

  • 當有兩個執行緒同時對資源進行操作的時候,如果沒有上鎖的話,這個執行緒對共享變數的操作還沒有結束並更新到主記憶體中取,其他的執行緒依然可能呼叫到共享的變數,這就會造成混亂。把這種現象叫做此執行緒對其他執行緒是不可見的。
  • 當有所的狀況下,先操作資源的執行緒要執行完成後,才會釋放鎖,這個時候其他的上了synchronized的方法或其他才能繼續操作資源資料。
  • synchronized的作用
    1、互斥
    正因為有了互斥,從而實現了synchronized塊執行緒執行的原子性:
    即一個執行緒在執行該synchronized塊的時候,其他執行緒是不會進來的
    除非當前執行緒釋放了資源鎖。
    2、記憶體可見
    正因為可以實現記憶體可見,所以可以通過主記憶體實現執行緒通訊。
  • 注意
    有synchronized的,一定可以實現記憶體可見。
    但反過來說,是不是沒有synchronized,就一定記憶體不可見呢?
    不一定。對於JVM而言,通常情況下,一個執行緒對共享的變數的更新一般會及時同步到主記憶體,對其他執行緒而言,通常是可見的。
    但這不是絕對的,只有加了synchronized,才能從根本上保證記憶體的可見。


  //使用synchronized修飾成員方法,實際上就是持有呼叫當前方法的物件的鎖

    public synchronized void saveMoney(){

        balance=1000;
    }

    public
synchronized int readMoney(){ return balance; } public void saveMoney2(){ synchronized (this) { balance=1000;
public class Tool {

    private Object object=new Object();

    private List<String> list=new ArrayList<>();

    /**
     * 1、使用synchronized修飾類方法的時候,現在上鎖的資源是類,而不是這個類的具體的某一個物件           
     * 2、如果synchronized上鎖的資源是類,對該類的例項物件是沒有影響的.
     *    即你不要認為你對類上了鎖,就對這個類的例項物件上了鎖
     * */
    public synchronized  void add(){

        for(int a=0;a<10;a++){
            System.out.println("a =  "+a);
            /*try {
                //執行緒在sleep的時候是不會釋放當前執行緒持有資源的鎖.
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/

            //yield()的作用讓渡CPU執行許可權,但是當前執行緒依然持有資源鎖,並不會釋放
            Thread.yield();

        }

    }


    public void save(){
        synchronized (this) {
            for(int b=0;b<10;b++){
                System.out.println("b =  "+b);
                /*try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                Thread.yield();
            }
        }
    }



    public void f1(){
        synchronized (this) {
            for(int a=0;a<10;a++){
                System.out.println("a =  "+a);


                Thread.yield();
            }
        }
    }
    /**
     * 即便是Dog繼承Animal,
     * 對於執行緒鎖而言,它只關注上鎖的具體的資源,而不關注其繼承關係。
     * */
    public void f2(){
        synchronized (this) {
            for(int b=0;b<10;b++){
                System.out.println("b =  "+b);
                Thread.yield();
            }
        }
    }








}
  • 對於執行緒鎖而言,它只關注上鎖的具體的資源,而不關注其繼承關係
  • 上鎖的範圍?
    上鎖的範圍不是指synchronized程式碼塊的範圍,而是指synchronized對應的上鎖的物件(資源)