国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 類加載之匿名類和主類相互依賴問題

LancerComet / 872人閱讀

摘要:匿名內(nèi)置類的初始化不能依賴于外部類的初始化表達(dá)式中作為主類字節(jié)碼的一部分,需要等待主類初始化完成才能開始執(zhí)行總之,在類的初始化階段,不能出現(xiàn)內(nèi)置類匿名和主類初始化中相互依賴的對(duì)象

Qestion
/**
 * ClassInitializedOrder for : Java Classload Order Test
 *
 * @author Isaac.Zhang | 若初
 * @since 2019/7/20
 */
// CASE 1  
public class ClassInitializedOrder {
    private static boolean initialized = false;
    static {
        println("static 代碼塊執(zhí)行。");
        Thread thread = new Thread(() -> initialized = true);
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        println("main 函數(shù)執(zhí)行。");
        System.out.println("initialized = " + initialized);
    }

    private static void println(Object o){
        System.out.println(o);
    }
}

-------------------------------------------------------------------
// CASE 2    
public class ClassInitializedOrder {
    private static boolean initialized = false;
    static {
        println("static 代碼塊執(zhí)行。");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                println("Runnable 代碼塊執(zhí)行。");
                initialized = true;
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        println("main 函數(shù)執(zhí)行。");
        System.out.println("initialized = " + initialized);
    }

    private static void println(Object o){
        System.out.println(o);
    }
Answer

A: initialized = true

B: initialized = false

C: 編譯錯(cuò)誤

D: 以上答案都是錯(cuò)的

Explain

程序執(zhí)行的時(shí)候,App Classloader 會(huì)首先加載ClassInitializedOrder.class, 按照類的順序依次執(zhí)行。

private static boolean initialized = false;

CASE 1

我們都知道,static塊會(huì)在類加載的時(shí)候初始化,那么下一步會(huì)執(zhí)行到Thread thread = new Thread(() -> initialized = true);我們先來看一下當(dāng)前行的字節(jié)碼:

static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=3, locals=2, args_size=0
         0: iconst_0
         1: putstatic     #7                  // Field initialized:Z
         4: new           #11                 // class java/lang/Thread
         7: dup
         8: invokedynamic #12,  0             // InvokeDynamic #0:run:()Ljava/lang/Runnable;
        13: invokespecial #13                 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        16: astore_0
        17: aload_0
        18: invokevirtual #14                 // Method java/lang/Thread.start:()V
        21: aload_0
        22: invokevirtual #15                 // Method java/lang/Thread.join:()V
        25: goto          33
        28: astore_1
        29: aload_1
        30: invokevirtual #17                 // Method java/lang/InterruptedException.printStackTrace:()V
        33: return

分析#12可以看到當(dāng)前行的處理需要()也就是改匿名類本身來處理,InvokeDynamic指令的在當(dāng)前的執(zhí)行又依賴于當(dāng)前所處的主類,主類并沒有執(zhí)行結(jié)束,因此它需要等待主類執(zhí)行結(jié)束,因此會(huì)在此停頓,如下:

CASE 2

繼續(xù)查看字節(jié)碼:

 static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=4, locals=2, args_size=0
         0: iconst_0
         1: putstatic     #1                  // Field initialized:Z
         4: ldc           #14                 // String static 代碼塊執(zhí)行。
         6: invokestatic  #2                  // Method println:(Ljava/lang/Object;)V
         9: new           #15                 // class java/lang/Thread
        12: dup
        13: new           #16                 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1
        16: dup
        17: invokespecial #17                 // Method com/sxzhongf/daily/question/july/ClassInitializedOrder$1."":()V
        20: invokespecial #18                 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        23: astore_0
        24: aload_0
        25: invokevirtual #19                 // Method java/lang/Thread.start:()V
        28: aload_0
        29: invokevirtual #20                 // Method java/lang/Thread.join:()V
        32: goto          40
        35: astore_1
        36: aload_1
        37: invokevirtual #22                 // Method java/lang/InterruptedException.printStackTrace:()V
        40: return

查看#16,我們可以看到這里變成了new #16 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1,可以明顯看到從之前的invokeDynamic 變成了 new 一個(gè)匿名類,那么它的結(jié)果呢?

依然還是block.我們來換一行代碼試試?

public class ClassInitializedOrder {
    private static boolean initialized = false;
    static {
        println("static 代碼塊執(zhí)行。");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //println("Runnable 代碼塊執(zhí)行。");
                System.out.println("Runnable 代碼塊執(zhí)行。");
                //initialized = true;
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

我們看到我們只是修改了一行代碼System.out.println("Runnable 代碼塊執(zhí)行。");,那么結(jié)果呢?

執(zhí)行成功的返回了。為什么?繼續(xù)查看字節(jié)碼

 static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=4, locals=2, args_size=0
         0: iconst_0
         1: putstatic     #9                  // Field initialized:Z
         4: ldc           #14                 // String static 代碼塊執(zhí)行。
         6: invokestatic  #3                  // Method println:(Ljava/lang/Object;)V
         9: new           #15                 // class java/lang/Thread
        12: dup
        13: new           #16                 // class com/sxzhongf/daily/question/july/ClassInitializedOrder$1
        16: dup
        17: invokespecial #17                 // Method com/sxzhongf/daily/question/july/ClassInitializedOrder$1."":()V
        20: invokespecial #18                 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        23: astore_0
        24: aload_0
        25: invokevirtual #19                 // Method java/lang/Thread.start:()V
        28: aload_0
        29: invokevirtual #20                 // Method java/lang/Thread.join:()V
        32: goto          40
        35: astore_1
        36: aload_1
        37: invokevirtual #22                 // Method java/lang/InterruptedException.printStackTrace:()V
        40: return

查看#16,看到的還是new了一個(gè)匿名類,和上一個(gè)是一樣的,為什么就可以成功呢?這個(gè)在于當(dāng)前匿名類中沒有依賴主類的代碼信息。不存在上下依賴,那么就不會(huì)出現(xiàn)相互等待的情況發(fā)生,當(dāng)然也就不會(huì)出現(xiàn)block。

那么就有朋友會(huì)問,為什么會(huì)相互等待呢?這里和我們join就有關(guān)聯(lián)了,我們來看一下它的實(shí)現(xiàn)代碼。

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

我們可以看到,首先它是synchronized關(guān)鍵詞修飾的,那就說明它同時(shí)只能被一個(gè)線程訪問,再往下看,我們能發(fā)現(xiàn),join的具體實(shí)現(xiàn),其實(shí)就是wait()來實(shí)現(xiàn),當(dāng)子線程中的程序再等待main線程的實(shí)現(xiàn)類初始化完成的時(shí)候,又依賴了主線程中的某些元素對(duì)象。那么就會(huì)開始等待主線程初始化完成,這個(gè)時(shí)候,根據(jù)classloader加載類的執(zhí)行順序,在#16就會(huì)開始等待,那么主類無法初始化完成,造成相互等待現(xiàn)相。

Result

匿名內(nèi)置類的初始化不能依賴于外部類的初始化

lambda表達(dá)式中invokeDynamic作為主類字節(jié)碼的一部分,需要等待主類初始化完成才能開始執(zhí)行

總之,在類的初始化階段,不能出現(xiàn)內(nèi)置類(匿名/Lambda)和主類初始化中相互依賴的對(duì)象

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75510.html

相關(guān)文章

  • 7. java 內(nèi)部

    摘要:外部類也可以直接訪問內(nèi)部類的所有屬性和方法。匿名內(nèi)部類為局部?jī)?nèi)部類,所以局部?jī)?nèi)部類的所有限制同樣對(duì)匿名內(nèi)部類生效。創(chuàng)建內(nèi)部類對(duì)象的時(shí)刻并不依賴于外圍類對(duì)象的創(chuàng)建。內(nèi)部類并沒有令人迷惑的關(guān)系,他就是一個(gè)獨(dú)立的實(shí)體。 基本概念 可以將一個(gè)類定義在另一個(gè)類里面或者一個(gè)方法里面,這樣的類稱為內(nèi)部類。 廣泛意義上的內(nèi)部類一般來說包括這四種: 成員內(nèi)部類 局部?jī)?nèi)部類 靜態(tài)內(nèi)部類 匿名內(nèi)部類 成...

    legendmohe 評(píng)論0 收藏0
  • Java編程中那些再熟悉不過的知識(shí)點(diǎn)(持續(xù)更新)

    摘要:語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時(shí)又保留了解釋型語言可移植的特點(diǎn)。有針對(duì)不同系統(tǒng)的特定實(shí)現(xiàn),,,目的是使用相同的字節(jié)碼,它們都會(huì)給出相同的結(jié)果。項(xiàng)目主要基于捐贈(zèng)的源代碼。 本文來自于我的慕課網(wǎng)手記:Java編程中那些再熟悉不過的知識(shí)點(diǎn),轉(zhuǎn)載請(qǐng)保留鏈接 ;) 1. 面向?qū)ο蠛兔嫦蜻^程的區(qū)別 面向過程 優(yōu)點(diǎn): 性能比面向?qū)ο蟾摺R驗(yàn)轭愓{(diào)用時(shí)需要實(shí)例...

    taowen 評(píng)論0 收藏0
  • Spring Boot 2.x基礎(chǔ)教程:工程結(jié)構(gòu)推薦

    摘要:典型示例以下結(jié)構(gòu)是比較推薦的組織方式,所有的類和其他都在之下。應(yīng)用主類,該類直接位于下。默認(rèn)情況下,的應(yīng)用主類會(huì)自動(dòng)掃描以及所有子包下的所有類來進(jìn)行初始化。 Spring Boot框架本身并沒有對(duì)工程結(jié)構(gòu)有特別的要求,但是按照最佳實(shí)踐的工程結(jié)構(gòu)可以幫助我們減少可能會(huì)遇見的坑,尤其是Spring包掃描機(jī)制的存在,如果您使用最佳實(shí)踐的工程結(jié)構(gòu),可以免去不少特殊的配置工作。 典型示例 以下結(jié)...

    CollinPeng 評(píng)論0 收藏0
  • 后端好書閱讀與推薦

    摘要:后端好書閱讀與推薦這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。高級(jí)程序設(shè)計(jì)高級(jí)程序設(shè)計(jì)第版豆瓣有人可能會(huì)有疑問,后端為啥要學(xué)呢其實(shí)就是為了更好的使用做鋪墊。 后端好書閱讀與推薦 這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。今天突然想要做個(gè)決定:每天至少花1-3小時(shí)用來看書。這里我準(zhǔn)備把這...

    clasnake 評(píng)論0 收藏0
  • 后端好書閱讀與推薦

    摘要:后端好書閱讀與推薦這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。高級(jí)程序設(shè)計(jì)高級(jí)程序設(shè)計(jì)第版豆瓣有人可能會(huì)有疑問,后端為啥要學(xué)呢其實(shí)就是為了更好的使用做鋪墊。 后端好書閱讀與推薦 這一兩年來養(yǎng)成了買書看書的習(xí)慣,陸陸續(xù)續(xù)也買了幾十本書了,但是一直沒有養(yǎng)成一個(gè)天天看書的習(xí)慣。今天突然想要做個(gè)決定:每天至少花1-3小時(shí)用來看書。這里我準(zhǔn)備把這...

    Juven 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<