乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      JVM字節(jié)碼指令集簡(jiǎn)介

       gaoshenmu 2016-09-11

      Java 虛擬機(jī)的指令由一個(gè)字節(jié)長(zhǎng)度的、代表著某種特定操作含義的操作碼(Opcode)以及跟隨其后的零至多個(gè)代表此操作所需參數(shù)的操作數(shù)(Operands)所構(gòu)成。虛擬機(jī)中許多指令并不包含操作數(shù),只有一個(gè)操作碼。

      如果忽略異常處理,那 Java 虛擬機(jī)的解釋器使用下面這個(gè)偽代碼的循環(huán)即可有效地工作:

      do{ 自動(dòng)計(jì)算PC寄存器以及從PC寄存器的位置取出操作碼; if(存在操作數(shù))取出操作數(shù); 執(zhí)行操作碼所定義的操作}while(處理下一次循環(huán));
      • 1
      • 2
      • 3
      • 4
      • 5

      操作數(shù)的數(shù)量以及長(zhǎng)度取決于操作碼,如果一個(gè)操作數(shù)的長(zhǎng)度超過(guò)了一個(gè)字節(jié),那它將會(huì)以 Big-Endian 順序存儲(chǔ)——即高位在前的字節(jié)序。舉個(gè)例子,如果要將一個(gè) 16 位長(zhǎng)度的無(wú)符號(hào)整數(shù)使用兩個(gè)無(wú)符號(hào)字節(jié)存儲(chǔ)起來(lái)(將它們命名為 byte1 和 byte2),那它們的值應(yīng)該是這樣的:

      (byte18)|byte2
      • 1

      字節(jié)碼指令流應(yīng)當(dāng)都是單字節(jié)對(duì)齊的,只有“tableswitch”和“l(fā)ookupswitch”兩條指令例外,由于它們的操作數(shù)比較特殊,都是以 4 字節(jié)為界劃分開(kāi)的,所以這兩條指令那個(gè)也需要預(yù)留出相應(yīng)的空位來(lái)實(shí)現(xiàn)對(duì)齊。

      限制 Java 虛擬機(jī)操作碼的長(zhǎng)度為一個(gè)字節(jié),并且放棄了編譯后代碼的參數(shù)長(zhǎng)度對(duì)齊,是為了盡可能地獲得短小精干的編譯代碼,即使這可能會(huì)讓 Java 虛擬機(jī)的具體實(shí)現(xiàn)付出一定的性能成本為代價(jià)。由于每個(gè)操作碼只能有一個(gè)字節(jié)長(zhǎng)度,所以直接限制了整個(gè)指令集的數(shù)量 (字節(jié)碼無(wú)法超過(guò) 256 條的限制就來(lái)源于此) ,又由于沒(méi)有假設(shè)數(shù)據(jù)是對(duì)齊好的,這就意味著虛擬機(jī)處理那些超過(guò)一個(gè)字節(jié)的數(shù)據(jù)的時(shí)候,不得不在運(yùn)行時(shí)從字節(jié)中重建出具體數(shù)據(jù)的結(jié)構(gòu),這在某種程度上會(huì)損失一些性能。

      數(shù)據(jù)類型與Java虛擬機(jī)

      在 Java 虛擬機(jī)的指令集中,大多數(shù)的指令都包含了其操作所對(duì)應(yīng)的數(shù)據(jù)類型信息。舉個(gè)例子,iload 指令用于從局部變量表中加載 int 型的數(shù)據(jù)到操作數(shù)棧中,而 fload 指令加載的則是 float 類型的數(shù)據(jù)。這兩條指令的操作可能會(huì)是由同一段代碼來(lái)實(shí)現(xiàn)的,但它們必須擁有各自獨(dú)立的操作符。

      對(duì)于大部分為與數(shù)據(jù)類型相關(guān)的字節(jié)碼指令,他們的操作碼助記符中都有特殊的字符來(lái)表明專門為哪種數(shù)據(jù)類型服務(wù):i 代表對(duì) int 類型的數(shù)據(jù)操作,l 代表 long,s 代表 short,b 代表 byte,c 代表 char,f 代表 float,d 代表 double,a 代表 reference。也有一些指令的助記符中沒(méi)有明確的指明操作類型的字母,例如 arraylength 指令,它沒(méi)有代表數(shù)據(jù)類型的特殊字符,但操作數(shù)永遠(yuǎn)只能是一個(gè)數(shù)組類型的對(duì)象。還有另外一些指令,例如無(wú)條件跳轉(zhuǎn)指令 goto 則是與數(shù)據(jù)類型無(wú)關(guān)的。

      由于 Java 虛擬機(jī)的操作碼長(zhǎng)度只有一個(gè)字節(jié),所以包含了數(shù)據(jù)類型的操作碼對(duì)指令集的設(shè)計(jì)帶來(lái)了很大的壓力:如果每一種與數(shù)據(jù)類型相關(guān)的指令都支持 Java 虛擬機(jī)所有運(yùn)行時(shí)數(shù)據(jù)類型的話,那恐怕就會(huì)超出一個(gè)字節(jié)所能表示的數(shù)量范圍了。因此,Java 虛擬機(jī)的指令集對(duì)于特定的操作只提供了有限的類型相關(guān)指令去支持它,換句話說(shuō),指令集將會(huì)故意被設(shè)計(jì)成非完全獨(dú)立的(Not Orthogonal,即并非每種數(shù)據(jù)類型和每一種操作都有對(duì)應(yīng)的指令)。有一些單獨(dú)的指令可以在必要的時(shí)候用來(lái)將一些不支持的類型轉(zhuǎn)換為可被支持的類型。

      下表列舉了 Java 虛擬機(jī)所支持的字節(jié)碼指令集,通過(guò)使用數(shù)據(jù)類型列所代表的特殊字符替換 opcode 列的指令模板中的 T,就可以得到一個(gè)具體的字節(jié)碼指令。如果在表中指令模板與數(shù)據(jù)類型兩列共同確定的格為空,則說(shuō)明虛擬機(jī)不支持對(duì)這種數(shù)據(jù)類型執(zhí)行這項(xiàng)操作。例如 load 指令有操作 int 類型的 iload,但是沒(méi)有操作 byte 類型的同類指令。

      請(qǐng)注意,從下表中看來(lái),大部分的指令都沒(méi)有支持整數(shù)類型 byte、char 和 short,甚至沒(méi)有任何指令支持 boolean 類型。編譯器會(huì)在編譯期或運(yùn)行期會(huì)將 byte 和 short 類型的數(shù)據(jù)帶符號(hào)擴(kuò)展(Sign-Extend)為相應(yīng)的 int 類型數(shù)據(jù),將 boolean 和 char 類型數(shù)據(jù)零位擴(kuò)展(Zero-Extend)為相應(yīng)的 int 類型數(shù)據(jù)。與之類似的,在處理 boolean、byte、short 和 char 類型的數(shù)組時(shí),也會(huì)轉(zhuǎn)換為使用對(duì)應(yīng)的 int 類型的字節(jié)碼指令來(lái)處理。因此,大多數(shù)對(duì)于 boolean、byte、short 和 char 類型數(shù)據(jù)的操作,實(shí)際上都是使用相應(yīng)的對(duì) int 類型作為運(yùn)算類型(Computational Type)。

      Java 虛擬機(jī)指令集所支持的數(shù)據(jù)類型:

      這里寫(xiě)圖片描述

      在 Java 虛擬機(jī)中,實(shí)際類型與運(yùn)算類型之間的映射關(guān)系,如下表所示:

      這里寫(xiě)圖片描述

      有部分對(duì)操作棧進(jìn)行操作的 Java 虛擬機(jī)指令(例如 pop 和 swap 指令)是與具體類型無(wú)關(guān)的,不過(guò)這些指令也必須受到運(yùn)算類型分類的限制,這些分類也在表中列出了。

      加載和存儲(chǔ)指令

      加載和存儲(chǔ)指令用于將數(shù)據(jù)從棧幀的局部變量表和操作數(shù)棧之間來(lái)回傳輸:

      1、將一個(gè)局部變量加載到操作棧的指令包括有:iload、iload_n>、lload、lload_n>、fload、fload_n>、dload、dload_n>、aload、aload_n>2、將一個(gè)數(shù)值從操作數(shù)棧存儲(chǔ)到局部變量表的指令包括有:istore、istore_n>、lstore、lstore_n>、fstore、fstore_n>、dstore、dstore_n>、astore、astore_n>3、將一個(gè)常量加載到操作數(shù)棧的指令包括有:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_i>、lconst_l>、fconst_f>、dconst_d>4、擴(kuò)充局部變量表的訪問(wèn)索引的指令:wide
      • 1
      • 2
      • 3
      • 4

      訪問(wèn)對(duì)象的字段或數(shù)組元素的指令也同樣會(huì)與操作數(shù)棧傳輸數(shù)據(jù)。

      上面所列舉的指令助記符中,有一部分是以尖括號(hào)結(jié)尾的(例如 iload_),這些指令助記符實(shí)際上是代表了一組指令(例如 iload_,它代表了 iload_0、iload_1、iload_2 和 iload_3 這幾條指令)。這幾組指令都是某個(gè)帶有一個(gè)操作數(shù)的通用指令(例如 iload)的特殊形式,對(duì)于這若干組特殊指令來(lái)說(shuō),它們表面上沒(méi)有操作數(shù),不需要進(jìn)行取操作數(shù)的動(dòng)作,但操作數(shù)都是在指令中隱含的。除此之外,他們的語(yǔ)義與原生的通用指令完全一致(例如 iload_0 的語(yǔ)義與操作數(shù)為 0 時(shí)的 iload 指令語(yǔ)義完全一致)。在尖括號(hào)之間的字母制定了指令隱含操作數(shù)的數(shù)據(jù)類型,代表是 int 形數(shù)據(jù),代表 long 型,代表 float 型,代表 double型。在操作 byte、char 和 short 類型數(shù)據(jù)時(shí),也用 int 類型表示。

      這種指令表示方法,在整個(gè)《Java 虛擬機(jī)規(guī)范》之中都是通用的。

      運(yùn)算指令

      算術(shù)指令用于對(duì)兩個(gè)操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)果重新存入到操作棧頂。大體上運(yùn)算指令可以分為兩種:對(duì)整型數(shù)據(jù)進(jìn)行運(yùn)算的指令與對(duì)浮點(diǎn)型數(shù)據(jù)進(jìn)行運(yùn)算的指令,無(wú)論是那種算術(shù)指令,都是使用 Java 虛擬機(jī)的數(shù)字類型的。數(shù)據(jù)沒(méi)有直接支持 byte、short、char 和 boolean 類型(§2.11.1)的算術(shù)指令,對(duì)于這些數(shù)據(jù)的運(yùn)算,都是使用操作 int 類型的指令。

      整數(shù)與浮點(diǎn)數(shù)的算術(shù)指令在溢出和被零除的時(shí)候也有各自不同的行為,所有的算術(shù)指令包括:

      加法指令:iadd、ladd、fadd、dadd 減法指令:isub、lsub、fsub、dsub 乘法指令:imul、lmul、fmul、dmul 除法指令:idiv、ldiv、fdiv、ddiv 求余指令:irem、lrem、frem、drem 取反指令:ineg、lneg、fneg、dneg 位移指令:ishl、ishr、iushr、lshl、lshr、lushr 按位或指令:ior、lor 按位與指令:iand、land 按位異或指令:ixor、lxor 局部變量自增指令:iinc 比較指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      Java 虛擬機(jī)的指令集直接支持了在《Java 語(yǔ)言規(guī)范》中描述的各種對(duì)整數(shù)及浮點(diǎn)數(shù)操作的語(yǔ)義。

      Java 虛擬機(jī)沒(méi)有明確規(guī)定整型數(shù)據(jù)溢出的情況,但是規(guī)定了在處理整型數(shù)據(jù)時(shí),只有除法指令(idiv 和 ldiv)以及求余指令(irem 和 lrem)出現(xiàn)除數(shù)為零時(shí)會(huì)導(dǎo)致虛擬機(jī)拋出異常,如果發(fā)生了這種情況,虛擬機(jī)將會(huì)拋出 ArithmeitcException 異常。

      Java 虛擬機(jī)在處理浮點(diǎn)數(shù)時(shí),必須遵循 IEEE 754 規(guī)范中所規(guī)定行為限制。也就是說(shuō) Java虛擬機(jī)要求完全支持 IEEE 754 中定義的非正規(guī)浮點(diǎn)數(shù)值(Denormalized Floating-Point Numbers,§2.3.2)和逐級(jí)下溢(Gradual Underflow)。這些特征將會(huì)使得某些數(shù)值算法處理起來(lái)變得更容易一些。

      Java 虛擬機(jī)要求在進(jìn)行浮點(diǎn)數(shù)運(yùn)算時(shí),所有的運(yùn)算結(jié)果都必須舍入到適當(dāng)?shù)倪M(jìn)度,非精確的結(jié)果必須舍入為可被表示的最接近的精確值,如果有兩種可表示的形式與該值一樣接近,那將優(yōu)先選擇最低有效位為零的。這種舍入模式也是 IEEE 754 規(guī)范中的默認(rèn)舍入模式,稱為向最接近數(shù)舍入模式。

      在把浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù)時(shí),Java 虛擬機(jī)使用 IEEE 754 標(biāo)準(zhǔn)中的向零舍入模式,這種模式的舍入結(jié)果會(huì)導(dǎo)致數(shù)字被截?cái)?,所有小?shù)部分的有效字節(jié)都會(huì)被丟棄掉。向零舍入模式將在目標(biāo)數(shù)值類型中選擇一個(gè)最接近,但是不大于原值的數(shù)字來(lái)作為最精確的舍入結(jié)果。

      Java 虛擬機(jī)在處理浮點(diǎn)數(shù)運(yùn)算時(shí),不會(huì)拋出任何運(yùn)行時(shí)異常(這里所講的是 Java 的異常,請(qǐng)勿與 IEEE 754 規(guī)范中的浮點(diǎn)異?;ハ嗷煜?,當(dāng)一個(gè)操作產(chǎn)生溢出時(shí),將會(huì)使用有符號(hào)的無(wú)窮大來(lái)表示,如果某個(gè)操作結(jié)果沒(méi)有明確的數(shù)學(xué)定義的話,將會(huì)時(shí)候 NaN 值來(lái)表示。所有使用 NaN 值作為操作數(shù)的算術(shù)操作,結(jié)果都會(huì)返回 NaN。

      在對(duì) long 類型數(shù)值進(jìn)行比較時(shí),虛擬機(jī)采用帶符號(hào)的比較方式,而對(duì)浮點(diǎn)數(shù)值進(jìn)行比較時(shí)(dcmpg、dcmpl、fcmpg、fcmpl),虛擬機(jī)采用 IEEE 754 規(guī)范說(shuō)定義的無(wú)信號(hào)比較(Nonsignaling Comparisons)方式。

      類型轉(zhuǎn)換指令

      類型轉(zhuǎn)換指令可以將兩種 Java 虛擬機(jī)數(shù)值類型進(jìn)行相互轉(zhuǎn)換,這些轉(zhuǎn)換操作一般用于實(shí)現(xiàn)用戶代碼的顯式類型轉(zhuǎn)換操作,或者用來(lái)處理 Java 虛擬機(jī)字節(jié)碼指令集中指令非完全獨(dú)立獨(dú)立的問(wèn)題。

      Java 虛擬機(jī)直接支持(注:“直接支持”意味著轉(zhuǎn)換時(shí)無(wú)需顯式的轉(zhuǎn)換指令)以下數(shù)值的寬化類型轉(zhuǎn)換(Widening Numeric Conversions,小范圍類型向大范圍類型的安全轉(zhuǎn)換):

      int 類型到 longfloat 或者 double 類型 long 類型到 float、double 類型 float 類型到 double 類型
      • 1
      • 2
      • 3
      • 4

      窄化類型轉(zhuǎn)換(Narrowing Numeric Conversions)指令包括有:i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l 和 d2f。窄化類型轉(zhuǎn)換可能會(huì)導(dǎo)致轉(zhuǎn)換結(jié)果產(chǎn)生不同的正負(fù)號(hào)、不同的數(shù)量級(jí),轉(zhuǎn)換過(guò)程很可能會(huì)導(dǎo)致數(shù)值丟失精度。

      在將 int 或 long 類型窄化轉(zhuǎn)換為整數(shù)類型 T 的時(shí)候,轉(zhuǎn)換過(guò)程僅僅是簡(jiǎn)單的丟棄除最低位N 個(gè)字節(jié)以外的內(nèi)容,N 是類型 T 的數(shù)據(jù)類型長(zhǎng)度,這將可能導(dǎo)致轉(zhuǎn)換結(jié)果與輸入值有不同的正負(fù)號(hào)(注:在高位字節(jié)符號(hào)位被丟棄了)。

      在將一個(gè)浮點(diǎn)值轉(zhuǎn)窄化轉(zhuǎn)換為整數(shù)類型 T(T 限于 int 或 long 類型之一)的時(shí)候,將遵循以下轉(zhuǎn)換規(guī)則:

      如果浮點(diǎn)值是 NaN,那轉(zhuǎn)換結(jié)果就是 int 或 long 類型的 0
      否則,如果浮點(diǎn)值不是無(wú)窮大的話,浮點(diǎn)值使用 IEEE 754 的向零舍入模式(§2.8.1)
      取整,獲得整數(shù)值 v,這時(shí)候可能有兩種情況:

      如果 T 是 long 類型,并且轉(zhuǎn)換結(jié)果在 long 類型的表示范圍之內(nèi),那就轉(zhuǎn)換為 long 類型數(shù)值 v 如果 T 是 int 類型,并且轉(zhuǎn)換結(jié)果在 int 類型的表示范圍之內(nèi),那就轉(zhuǎn)換為 int 類型數(shù)值 v否則: 如果轉(zhuǎn)換結(jié)果 v 的值太?。òㄗ銐蛐〉呢?fù)數(shù)以及負(fù)無(wú)窮大的情況),無(wú)法使用 T 類 型表示的話,那轉(zhuǎn)換結(jié)果取 int 或 long 類型所能表示的最小數(shù)字。 如果轉(zhuǎn)換結(jié)果 v 的值太大(包括足夠大的正數(shù)以及正無(wú)窮大的情況),無(wú)法使用 T 類 型表示的話,那轉(zhuǎn)換結(jié)果取 int 或 long 類型所能表示的最大數(shù)字。

      從 double 類型到 float 類型做窄化轉(zhuǎn)換的過(guò)程與 IEEE 754 中定義的一致,通過(guò) IEEE 754向最接近數(shù)舍入模式(§2.8.1)舍入得到一個(gè)可以使用 float 類型表示的數(shù)字。如果轉(zhuǎn)換結(jié)果的絕對(duì)值太小無(wú)法使用 float 來(lái)表示的話,將返回 float 類型的正負(fù)零。如果轉(zhuǎn)換結(jié)果的絕對(duì)值太大無(wú)法使用 float 來(lái)表示的話,將返回 float 類型的正負(fù)無(wú)窮大,對(duì)于 double 類型的 NaN值將就規(guī)定轉(zhuǎn)換為 float 類型的 NaN 值。

      盡管可能發(fā)生上限溢出、下限溢出和精度丟失等情況,但是 Java 虛擬機(jī)中數(shù)值類型的窄化轉(zhuǎn)換永遠(yuǎn)不可能導(dǎo)致虛擬機(jī)拋出運(yùn)行時(shí)異常(此處的異常是指《Java 虛擬機(jī)規(guī)范》中定義的異常,請(qǐng)讀者不要與 IEEE 754 中定義的浮點(diǎn)異常信號(hào)產(chǎn)生混淆)。

      對(duì)象創(chuàng)建與操作

      雖然類實(shí)例和數(shù)組都是對(duì)象,但 Java 虛擬機(jī)對(duì)類實(shí)例和數(shù)組的創(chuàng)建與操作使用了不同的字節(jié)碼指令:

      1、創(chuàng)建類實(shí)例的指令:new

      2、創(chuàng)建數(shù)組的指令:newarray,anewarray,multianewarray

      3、訪問(wèn)類字段(static 字段,或者稱為類變量)和實(shí)例字段(非 static 字段,或者成為實(shí)例變量)的指令:getfield、putfield、getstatic、putstatic

      4、把一個(gè)數(shù)組元素加載到操作數(shù)棧的指令:baload、caload、saload、iaload、laload、faload、daload、aaload

      5、將一個(gè)操作數(shù)棧的值儲(chǔ)存到數(shù)組元素中的指令:bastore、castore、sastore、iastore、fastore、dastore、aastore

      6、取數(shù)組長(zhǎng)度的指令:arraylength

      7、檢查類實(shí)例類型的指令:instanceof、checkcas

      操作數(shù)棧管理指令

      Java 虛擬機(jī)提供了一些用于直接操作操作數(shù)棧的指令,包括:pop、pop2、dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2 和 swap。

      控制轉(zhuǎn)移指令

      控制轉(zhuǎn)移指令可以讓 Java 虛擬機(jī)有條件或無(wú)條件地從指定指令而不是控制轉(zhuǎn)移指令的下一條指令繼續(xù)執(zhí)行程序。控制轉(zhuǎn)移指令包括有:

      1、條件分支:ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt, if_icmpgt、if_icmple、if_icmpge、if_acmpeq 和 if_acmpne。

      2、復(fù)合條件分支:tableswitch、lookupswitch

      3、無(wú)條件分支:goto、goto_w、jsr、jsr_w、ret

      在 Java 虛擬機(jī)中有專門的指令集用來(lái)處理 int 和 reference 類型的條件分支比較操作,為了可以無(wú)需明顯標(biāo)識(shí)一個(gè)實(shí)體值是否 null,也有專門的指令用來(lái)檢測(cè) null 值。

      boolean 類型、byte 類型、char 類型和 short 類型的條件分支比較操作,都使用 int 類型的比較指令來(lái)完成,而對(duì)于 long 類型、float 類型和 double 類型的條件分支比較操作,則會(huì)先執(zhí)行相應(yīng)類型的比較運(yùn)算指令,運(yùn)算指令會(huì)返回一個(gè)整形值到操作數(shù)棧中,隨后再執(zhí)行 int 類型的條件分支比較操作來(lái)完成整個(gè)分支跳轉(zhuǎn)。由于各種類型的比較最終都會(huì)轉(zhuǎn)化為 int 類型的比較操作,基于 int 類型比較的這種重要性,Java 虛擬機(jī)提供了非常豐富的 int類型的條件分支指令。

      所有 int 類型的條件分支轉(zhuǎn)移指令進(jìn)行的都是有符號(hào)的比較操作。

      方法調(diào)用和返回指令

      以下四條指令用于方法調(diào)用:

      1、invokevirtual 指令用于調(diào)用對(duì)象的實(shí)例方法,根據(jù)對(duì)象的實(shí)際類型進(jìn)行分派(虛方法分派),這也是 Java 語(yǔ)言中最常見(jiàn)的方法分派方式。

      2、invokeinterface 指令用于調(diào)用接口方法,它會(huì)在運(yùn)行時(shí)搜索一個(gè)實(shí)現(xiàn)了這個(gè)接口方法的對(duì)象,找出適合的方法進(jìn)行調(diào)用。

      3、invokespecial 指令用于調(diào)用一些需要特殊處理的實(shí)例方法,包括實(shí)例初始化方法、私有方法和父類方法。

      4、invokestatic 指令用于調(diào)用類方法(static 方法)。

      而方法返回指令則是根據(jù)返回值的類型區(qū)分的,包括有 ireturn(當(dāng)返回值是 boolean、byte、char、short 和 int 類型時(shí)使用)、lreturn、freturn、dreturn 和 areturn,另外還有一條 return 指令供聲明為 void 的方法、實(shí)例初始化方法、類和接口的類初始化方法使用。

      拋出異常

      在程序中顯式拋出異常的操作會(huì)由 athrow 指令實(shí)現(xiàn),除了這種情況,還有別的異常會(huì)在其它 Java 虛擬機(jī)指令檢測(cè)到異常狀況時(shí)由虛擬機(jī)自動(dòng)拋出。

      同步

      Java 虛擬機(jī)可以支持方法級(jí)的同步和方法內(nèi)部一段指令序列的同步,這兩種同步結(jié)構(gòu)都是使用管程(Monitor)來(lái)支持的。

      方法級(jí)的同步是隱式,即無(wú)需通過(guò)字節(jié)碼指令來(lái)控制的,它實(shí)現(xiàn)在方法調(diào)用和返回操作之中。虛擬機(jī)可以從方法常量池中的方法表結(jié)構(gòu)(method_info Structure)中的 ACC_SYNCHRONIZED 訪問(wèn)標(biāo)志區(qū)分一個(gè)方法是否同步方法。當(dāng)方法調(diào)用時(shí),調(diào)用指令將會(huì)檢查方法的 ACC_SYNCHRONIZED 訪問(wèn)標(biāo)志是否被設(shè)置,如果設(shè)置了,執(zhí)行線程將先持有管程,然后再執(zhí)行方法,最后再方法完成(無(wú)論是正常完成還是非正常完成)時(shí)釋放管程。在方法執(zhí)行期間,執(zhí)行線程持有了管程,其他任何線程都無(wú)法再獲得同一個(gè)管程。如果一個(gè)同步方法執(zhí)行期間拋出了異常,并且在方法內(nèi)部無(wú)法處理此異常,那這個(gè)同步方法所持有的管程將在異常拋到同步方法之外時(shí)自動(dòng)釋放。

      同步一段指令集序列通常是由 Java 語(yǔ)言中的 synchronized 塊來(lái)表示的,Java 虛擬機(jī)的指令集中有 monitorenter 和 monitorexit 兩條指令來(lái)支持 synchronized 關(guān)鍵字的語(yǔ)義,正確實(shí)現(xiàn) synchronized 關(guān)鍵字需要編譯器與 Java 虛擬機(jī)兩者協(xié)作支持。

      結(jié)構(gòu)化鎖定(Structured Locking)是指在方法調(diào)用期間每一個(gè)管程退出都與前面的管程進(jìn)入相匹配的情形。因?yàn)闊o(wú)法保證所有提交給 Java 虛擬機(jī)執(zhí)行的代碼都滿足結(jié)構(gòu)化鎖定,所以 Java 虛擬機(jī)允許(但不強(qiáng)制要求)通過(guò)以下兩條規(guī)則來(lái)保證結(jié)構(gòu)化鎖定成立。假設(shè) T 代表一條線程,M 代表一個(gè)管程的話:

      1、T 在方法執(zhí)行時(shí)持有管程 M 的次數(shù)必須與 T 在方法完成(包括正常和非正常完成)時(shí)釋放管程 M 的次數(shù)相等。

      2、找方法調(diào)用過(guò)程中,任何時(shí)刻都不會(huì)出現(xiàn)線程 T 釋放管程 M 的次數(shù)比 T 持有管程 M 次數(shù)多的情況。

      請(qǐng)注意,在同步方法調(diào)用時(shí)自動(dòng)持有和釋放管程的過(guò)程也被認(rèn)為是在方法調(diào)用期間發(fā)生。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多