JVM 線程中方法執行過程

 本章節內容參考:《深刻理解Java虛擬機》java

運行時數據區:緩存

 

 本次只介紹用於程序運行的線程私有的內存模型。   多線程

                虛擬機棧(FILO):java方法執行的內存模型。this

                    棧幀(線程執行的一個方法的內存模型,每調用一個方法,壓入一個棧幀)線程

                              局部變量表:編譯器可知的8種基本類型、reference類型、returnAddress類型對象

                              操做數棧:一個用於計算的臨時數據存儲區(明顯,此棧是爲了存放要操做的數據用的)blog

                              動態連接:支持java多態索引

                              返回地址:方法結束的地方。return/Exception        ip

                本地方法棧:Native方法執行的內存模型。內存

                程序計數器:這個計數器記錄的是正在執行的虛擬機字節碼指令的地址(若是線程正在執行的是一個java方法)。 字節碼解釋器工做時,就是經過改變這個計數器的值來選取須要執行的字節碼                                         指令(分支,循環,跳轉、異常處理、線程恢復)

 

線程中,方法A調用方法B。

 

線程的執行的過程:

    一、線程開始,分配虛擬機棧大小(JVM參數 -Xss:大小,1.5+默認1M),

         二、執行方法A時,建立一個棧幀A壓入虛擬機棧頂,根據程序計數器中的記錄的下一個要執行的字節碼指令的地址,找到並執行指令(將要操做的數據壓入操做數棧棧頂,將操做結果放入局部變量表中,詳細過程參照下面「合代碼演示」部分)。

        三、中間調用方法B,則建立棧幀B,接着執行方法B的指令,直到方法B結束(遇到方法返回的字節碼指令或異常),B棧幀出棧,若是有返回數據,將返回數據壓入棧幀A的操做數棧頂,方法A接着執行。 

  四、方法A執行結束,彈出棧幀A,虛擬機棧中再無棧幀,此線程結束。 

 

爲更形象的理解,結合代碼演示(操做數棧和局部變量表):

源碼:

25.      public void add() {

26.           int a = 3;

27.           int b = 4;

28.           int c = a + b;

29.     }

javap結果:

public void add();

    descriptor: ()V

    flags: ACC_PUBLIC

    Code:

  //操做數棧最大深度2,局部變量4, 方法入參1(this + 真正的入參, 若是是方法名add(int a, int b),args_size = 1(this) + 2(a和b) = 3)

       stack=2,   locals=4, args_size=1

         0: iconst_3     // 將int類型常量3壓入操做數棧頂

         1: istore_1     // 將操做數棧頂的數據彈出,存入局部變量表索引1

         2: iconst_4     // 將int類型常量4壓入操做數棧棧頂

         3: istore_2     // 將操做數棧頂的數據彈出,存入局部變量表索引2

         4: iload_1      // 將局部變量表索引爲1的數據加入到操做數棧頂

         5: iload_2      // 將局部變量表索引爲2的數據加入到操做數棧頂

         6: iadd          // 將棧中2個數相加,將結果入棧頂 

         7: istore_3     // 將棧頂結果彈出,存入局部變量表索引3

         8: return

      LineNumberTable:

        line 26: 0 //java文件代碼第26行對應開始指令0

        line 27: 2 //java文件代碼第26行對應開始指令2

        line 28: 4 //java文件代碼第26行對應開始指令4

        line 29: 8 //java文件代碼第26行對開始應指令8

      LocalVariableTable:  // 局部變量表,4個局部變量,this、a、b、c

        Start  Length  Slot  Name   Signature

            0       9     0  this   LCongoPengYuyan;         

            2       7     1     a   I

            4       5     2     b   I

            8       1     3     c   I

 

一些思考:

  咱們都知道,操做數棧存放的數據是(int、long、float、double、reference、returnType)這些類型,

  reference指像的對象是在堆裏面,堆是共享的,既然是全部線程共享的,爲啥在多線程中,數據會不一致呢,線程A將對象O的某個屬性改了,而線程B拿到O的屬性的值仍是未改變的?java還推出了統一的JMM模型。

       其實,CPU執行的時候,是要將內存中的數據,加載到CPU緩存(寄存器等),多線程的時候,數據首先在寄存器中修改,改完後從新刷入內存中。解決多線程數據可見性的問題,java提供了Volatile關鍵字,

  它的實現原理,對象操做後面加入Lock彙編指令。A線程在修改操做後,強制刷入主存,而後通知執行B線程的CPU,你CPU緩存中的值是失效,不能用了,要用請從主存中從新獲取。

相關文章
相關標籤/搜索