中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-07-10 15:16:14 來源:網絡 閱讀:573 作者:zhangpan0614 欄目:編程語言

Qestion

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

    public static void main(String[] args) {
        println("main 函數執行。");
        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 代碼塊執行。");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                println("Runnable 代碼塊執行。");
                initialized = true;
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

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

Answer

  • A: initialized = true
  • B: initialized = false
  • C: 編譯錯誤
  • D: 以上答案都是錯的

Explain

程序執行的時候,App Classloader 會首先加載ClassInitializedOrder.class, 按照類的順序依次執行。

private static boolean initialized = false;

CASE 1

我們都知道,static塊會在類加載的時候初始化,那么下一步會執行到Thread thread = new Thread(() -&gt; initialized = true);我們先來看一下當前行的字節碼:

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."<init>":(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可以看到當前行的處理需要()也就是改匿名類本身來處理,InvokeDynamic指令的在當前的執行又依賴于當前所處的主類,主類并沒有執行結束,因此它需要等待主類執行結束,因此會在此停頓,如下:

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

CASE 2

繼續查看字節碼:

 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 代碼塊執行。
         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."<init>":()V
        20: invokespecial #18                 // Method java/lang/Thread."<init>":(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 一個匿名類,那么它的結果呢?

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

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

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

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

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

執行成功的返回了。為什么?繼續查看字節碼

 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 代碼塊執行。
         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."<init>":()V
        20: invokespecial #18                 // Method java/lang/Thread."<init>":(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了一個匿名類,和上一個是一樣的,為什么就可以成功呢?這個在于當前匿名類中沒有依賴主類的代碼信息。不存在上下依賴,那么就不會出現相互等待的情況發生,當然也就不會出現block。

那么就有朋友會問,為什么會相互等待呢?這里和我們join就有關聯了,我們來看一下它的實現代碼。

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關鍵詞修飾的,那就說明它同時只能被一個線程訪問,再往下看,我們能發現,join的具體實現,其實就是wait()來實現,當子線程中的程序再等待main線程的實現類初始化完成的時候,又依賴了主線程中的某些元素對象。那么就會開始等待主線程初始化完成,這個時候,根據classloader加載類的執行順序,在#16就會開始等待,那么主類無法初始化完成,造成相互等待現相。

Result

  • 匿名內置類的初始化不能依賴于外部類的初始化
  • lambda表達式中invokeDynamic作為主類字節碼的一部分,需要等待主類初始化完成才能開始執行

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临西县| 永寿县| 漳平市| 乌兰浩特市| 康保县| 沙湾县| 嘉义县| 益阳市| 永丰县| 汉阴县| 南安市| 固原市| 含山县| 新龙县| 杭锦旗| 涡阳县| 平乐县| 特克斯县| 灵台县| 蒙山县| 大渡口区| 平谷区| 长海县| 肇州县| 上饶县| 黎平县| 聂荣县| 噶尔县| 古蔺县| 沙洋县| 桂平市| 金山区| 乌苏市| 普格县| 榆树市| 视频| 富平县| 大足县| 诸暨市| 比如县| 乐亭县|