Как читать исходный код jdk?

Java

🖕Приглашаем обратить внимание на мой публичный аккаунт «Брат Тонг читает исходный код», ознакомиться с другими статьями из серии исходного кода и поплавать в океане исходного кода вместе с братом Тонгом.


Введение

В этой статье в основном описывается, как читать исходный код самого jdk, чтение исходного кода различных фреймворков мы обсудим позже.

Автор считает, что чтение исходного кода в основном включает следующие шаги.

поставить цель

У всего есть цель, как и у чтения исходного кода.

С большой точки зрения, цель чтения исходного кода состоит в том, чтобы улучшить наши технические возможности, применить их в своей работе, быстро выявить проблемы, получить продвижение по службе и повышение заработной платы и т. д.

С небольшой точки зрения цель чтения определенного исходного кода состоит в том, чтобы понять его принцип, то есть умереть, то есть своего рода упрямство, чтобы исследовать правду.

Цель абстрактна, цель конкретна, мы должны поставить перед собой цель, прежде чем читать исходный код.

Например, для ConcurrentHashMap, который мы вместе изучим в следующей главе, мы можем поставить следующие цели:

(1) Знаком со структурой хранения ConcurrentHashMap;

(2) Знаком с процессом реализации основных методов ConcurrentHashMap;

(3) изучить новые технологии, появляющиеся в ConcurrentHashMap;

Задайте вопрос

Теперь, когда у нас есть цель, давайте попробуем задать несколько вопросов.

Взяв за пример ConcurrentHashMap, автор поднял следующие вопросы:

(1) Является ли структура данных ConcurrentHashMap и HashMap одинаковой?

(2) Когда у HashMap возникнут проблемы с безопасностью в многопоточной среде?

(3) Как ConcurrentHashMap решает проблему безопасности параллелизма?

(4) Какие блокировки использует ConcurrentHashMap?

(5) Как осуществляется расширение ConcurrentHashMap?

(6) Является ли ConcurrentHashMap сильной согласованностью?

(7) Какие проблемы не может решить ConcurrentHashMap?

(8) Помимо безопасности параллелизма, в чем разница между ConcurrentHashMap и HashMap и почему ее следует реализовать?

(8) Какие необычные приемы в ConcurrentHashMap стоит изучить?

Как задавать вопросы

Многие люди скажут: я умею задавать вопросы, но как их задавать?

Это действительно очень сложная вещь, и я думаю, что есть три основных момента:

(1) спросите себя

Думайте о себе как о интервьюере, спрашивающем себя, о том, как вы спрашиваете себя до смерти.

Неважно, если вы не можете задать себе несколько вопросов, см. ниже.

(2) Спросите в Интернете

Многие вопросы могут не прийти в голову вам самим, поэтому вам нужно выйти в интернет и проверить соответствующие блоги, чтобы узнать, не возникали ли у других какие-либо вопросы.

Или проверьте связанные вопросы интервью.

Например, когда я изучал класс ConcurrentHashMap, многие из них были основаны на jdk7, когда я проверял онлайн, в это время я могу задать вопрос, в чем разница между реализацией класса ConcurrentHashMap в jdk8 и jdk7? Какие оптимизации сделал jdk8 для jdk7?

(3) Постоянно находить проблемы

В процессе чтения исходного кода вы можете столкнуться с проблемой при просмотре, это очень распространено, и такого рода проблемы также должны быть сохранены для исследования.

Например, как реализован метод size() в ConcurrentHashMap?@sun.misc.ContendedЧто, черт возьми, это за штука? Затем я проверил Интернет и, чтобы избежать ложного обмена, IX,伪共享Что это? Затем вы снова проверяете伪共享, а из процессорного многоуровневого кеша? Изучив многоуровневый кеш процессора, считаете ли вы его очень похожим на модель памяти JVM? После того, как вы задали эту серию вопросов, чувствуете ли вы, что мир стал ясным? ^_^

Видите, проблемы обнаруживаются непрерывным потоком.

Поэтому не имеет значения, если вы не зададите несколько вопросов в начале, ключ в том, чтобы посмотреть на это, и тогда вы сможете найти больше проблем.

Читайте исходный код с вопросами, игнорируйте ненужные детали и придерживайтесь важных деталей.

Во-первых, обязательно прочитайте исходный код с вопросами.

Во-вторых, обязательно игнорируйте ненужные детали.

Опять же, обязательно придерживайтесь важных деталей.

На первый взгляд последние два шага кажутся противоречивыми, но это не так.Игнорирование ненужных деталей позволяет не потеряться в мире исходного кода, а придерживаться важных деталей — чтобы узнать правду об исходном коде.

Игнорируются ли детали здесь или упорно упорствуют, в основном зависит от актуальности проблемы.

Исходный код jdk по-прежнему относительно легко читается. Если вы посмотрите на исходный код Spring позже, вы потеряетесь, если не сможете игнорировать ненужные детали. Давайте сначала заложим предзнаменование~~

Например, прочитайте метод readObject() в коде, связанном с сериализацией ArrayList ранее.

s.readInt();Для чего эта строка? Можете ли вы опустить это? В это время необходимо понять знания, связанные с сериализацией, а затем посмотреть на реализацию в writeObject().Этот код должен умереть.

SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);Для чего эта строка? На первый взгляд кажется, что код, связанный с разрешениями, не имеет никакого отношения к нашей проблеме "сериализации", не обращайте на него внимания, если очень хотите узнать, сначала отметьте, а потом уже изучайте это дело после решения проблемы сериализации .

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
    // 声明为空数组
    elementData = EMPTY_ELEMENTDATA;

    // 读入非transient非static属性(会读取size属性)
    s.defaultReadObject();

    // 读入元素个数,没什么用,只是因为写出的时候写了size属性,读的时候也要按顺序来读
    s.readInt();

    if (size > 0) {
        // 计算容量
        int capacity = calculateCapacity(elementData, size);
        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
        // 检查是否需要扩容
        ensureCapacityInternal(size);
        
        Object[] a = elementData;
        // 依次读取元素到数组中
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

Делайте больше сравнений

При чтении исходного кода jdk также важно делать больше сравнений.Сравнения также можно разделить на горизонтальные сравнения и вертикальные сравнения.

(1) Горизонтальное сравнение

Это для сравнения с аналогичными классами. Например, в модуле сбора вставляются, запрашиваются и удаляются в основном все виды элементов.В это время сравнение может быть выполнено по размерам структуры данных и временной сложности, что является горизонтальным сравнением.

(2) Вертикальное сравнение

Сравнения можно сделать из истории развития коллекции. Например, история разработки HashMap, начиная с реализации (одного массива) (да, HashMap можно реализовать напрямую с массивом), до реализации (несколько массивов + связанный список), а затем до jdk8 (несколько массивов + связанный список + красный -черное дерево) Поймите, это вертикальное сравнение.

Делайте больше экспериментов

Последний и самый важный шаг — провести больше экспериментов.

Например, является ли ConcurrentHashMap строго последовательным?

Вы можете запустить несколько потоков для непрерывного вызова методов get(), put() и size(), чтобы проверить, существует ли строгая согласованность.

пасхальные яйца

Упс, случайно раскрыл содержимое ConcurrentHashMap в следующей главе.

Вы можете использовать метод, упомянутый в этой статье, чтобы попытаться прочитать исходный код ConcurrentHashMap, и мы будем учиться вместе в следующей главе, ха-ха~~


Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись «Брат Тонг читает исходный код», проверить больше статей из серии исходного кода и поплавать в океане исходного кода с братом Тонгом.

qrcode