翻車現場一:由synchronized的使用場景引發 static和this關鍵字你真的瞭解嗎

前言

我們在開發的時候往往會忽略java知識的一些細節使用,但是這些細節點往往是面試的時候比較關注的,下面總結下面試過程中容易翻車的一些細節點,供大家參考。

synchronized的使用場景可以歸結爲3種:

① 修飾靜態方法,給當前類對象加鎖,進入同步方法時需要獲得類對象的鎖
② 修飾實例方法,給當前實例變量加鎖,進入同步方法時需要獲得當前實例的鎖
③ 修飾同步方法塊,指定加鎖對象(可以是實例對象,也可以是類變量),對給定對象加鎖,進入同步方法塊時需要獲得加鎖對象的鎖

1、靜態方法

Class BankAccount{
      private static int accountNum; // 一共有多少個銀行賬號
      
      public static synchronized void setAccountNum(){
                accountNum = accountNum + 1;
      }
}

2、成員方法

public class BankAccount{
        private double balance;
        private static Logger logger = LoggerFactory.getLogger(BankAccount.class);

        public synchronized void deposite(double moneyToAdd){
                String threadName = Thread.currentThread().getName();
                logger.info(threadName + "--當前銀行餘額爲:" + this.balance);
                balance = balance + moneyToAdd;
                logger.info(threadName + "--存後銀行餘額爲:" + this.balance);
        }
}

3、同步代碼塊,塊對象是實例對象

public class BankAccount{
        private double balance;
        private static Logger logger = LoggerFactory.getLogger(BankAccount.class);

        public void deposite(double moneyToAdd){
                String threadName = Thread.currentThread().getName();
                logger.info(threadName + "--當前銀行餘額爲:" + this.balance);
                synchronized(this){
                      balance = balance + moneyToAdd;
                }
                logger.info(threadName + "--存後銀行餘額爲:" + this.balance);
        }
}

4、同步代碼塊,塊對象是類對象

Class BankAccount{
      private static int accountNum; // 一共有多少個銀行賬號
      
      public synchronized void setAccountNum(){
          synchronized(BankAccount.class){
                 accountNum = accountNum + 1;
          }  
      }
}

synchronized 修飾在 static方法和非static方法的區別

static的方法屬於類方法,它屬於這個Class(注意:這裏的Class不是指Class的某個具體對象),那麼static獲取到的鎖,是屬於類的鎖。而非static方法獲取到的鎖,是屬於當前對象的鎖。所以,他們之間不會產生互斥。

public class Aa{
static synchronized void bb(){}
static synchronized void cc(){}
}

當兩個線程同時分別訪問 bb 和 cc 方法時,此時只有bb方法執行完畢,纔會執行cc。

靜態變量

  • 一種是被static修飾的變量,叫靜態變量或類變量
  • ​​​另一種是沒有被static修飾的變量,叫實例變量

兩者的區別是:
   對於靜態變量在內存中只有一個(節省內存),JVM只爲靜態變量分配一次內存,在加載類的過程中完成靜態變量的內存分配,可用類名直接訪問(方便),當然也可以通過對象來訪問(但是這是不推薦的)。
    對於實例變量,每創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響(靈活)。

靜態方法

  • 非靜態方法既可以訪問靜態數據成員又可以訪問非靜態數據成員,而靜態方法只能訪問靜態數據成員; 
  • 非靜態方法既可以訪問靜態數據方法又可以訪問非靜態數據方法,而靜態方法只能訪問靜態數據方法。 

原因:因爲靜態方法和靜態數據成員會隨着類的定義而被分配和裝載入內中;而非靜態方法和非靜態數據成員只有在類的對象創建時在對象的內存中才有這個方法的代碼段。此時還不存在內存中,所以不能調用。

靜態代碼塊

那什麼是靜態代碼塊呢?說白了,靜態代碼塊就是用static修飾的代碼塊  特點:隨着類的加載而執行,而且只執行一次

static方法中不能使用this

Static方法是類方法,先於任何的實例(對象)存在。即Static方法在類加載時就已經存在了,但是對象是在創建時纔在內存中生成。而this指代的是當前的對象 在方法中定義使用的this關鍵字,它的值是當前對象的引用.被static修飾的成員變量和成員方法獨立於該類的任何對象。static表示不要實例化就可以使用。

this關鍵字

Java提供了一個this關鍵字,this關鍵字總是指向調用該方法的對象。根據this出現的位置的不同,this作爲對象的默認引用有兩種情形。

  1. 構造器中引用該構造器正在初始化的對象。
  2. 在方法中引用調用該方法的對象。

this可以代表任何對象,當this出現在某個方法體中時,它所代表的對象是不確定的,但它的類型是確定的,它所代表的類型只能是當前類:只有當這個方法被調用時,它所代表的對象才被確定下來:誰在調用這個方法,this就代表誰。

//定義一個eat()方法,eat()方法需要藉助move()方法
public void eat(){
    //使用this引用調用eat()方法的對象
    this.move();
    System.out.println("正在執行eat()方法");
}

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