Предисловие
Это довольно холодно в течение этого периода, поэтому я посмотрел на исходный код JDK. Генеральный старший инженер по разработке может улучшить себя, прочитав какой -то исходный код. В этой статье суммируются некоторые «небольшие советы» в исходном коде JDK и делят их для вашей ссылки и обучения. Я не скажу многое ниже, давайте посмотрим на подробное введение вместе.
1 i ++ vs i--
Строка 985 Строкового исходного кода, в методе равных
while (n-! = 0) {if (v1 [i]! = v2 [i]) вернуть false; i ++; }Этот кодекс используется, чтобы судить, является ли строка равной, но есть странная вещь, которая использует i-! = 0 для вынесения суждений. Разве мы не используем i ++? Зачем использовать я ...? И количество циклов одинаково. Причина в том, что после сборника будет еще одна инструкция:
I-- Сама операция повлияет на CPSR (текущий регистр состояния программы). Общие флаги для CPSR являются N (результат отрицательный), z (результат равен 0), C (переноски) и O (переполнение). Я> 0, можно прямо оценить флагом Z.
Операция I ++ также повлияет на CPSR (текущий реестр статуса программы), но только затронет флаг O (с переполнением), который не поможет в решении I <n. Следовательно, необходима дополнительная инструкция по сравнению, что означает, что для каждого цикла должна быть выполнена еще одна инструкция.
Проще говоря, по сравнению с 0, будет на одну инструкцию. Поэтому утилизация I-высококачественного, атмосферного и высокого класса.
2 переменные члена против локальных переменных
Исходный код JDK почти использует локальную переменную для принятия переменных членов в любом методе, например,
public int compareto (String anotherstring) {int len1 = value.length; int len2 = anotherstring.value.length;Поскольку локальные переменные инициализируются в стеке потоков метода, в то время как переменные элемента инициализируются в памяти кучи, очевидно, что первое быстрее, поэтому мы стараемся избегать использования переменных элементов непосредственно в методе, но вместо этого используем локальные переменные.
3 намеренно загрузка в регистры и поместите много трудоемких операций за пределами блокировки
В concurrenthashmap операция сегмента блокировки очень интересна. Это не прямой замк, но похож на спин -блокировку. Это неоднократно пытается приобрести замок. Во время процесса получения блокировки он будет пересекать связанный список, так что данные сначала будут загружены в кэш регистра, избегая удобства в процессе блокировки. В то же время операция генерации новых объектов также помещается за пределы замка, чтобы избежать трудоемких операций в блокировке
final v Put (k Key, int hash, v Значение, Boolean onlyifabsent) { /** Перед написанием этого сегмента необходимо сначала получить исключительный замок сегмента. Это не для того, чтобы заставлять lock (), а попробовать*/ Hashentry <K, v> node = trylock ()? null: scanandlockforput (ключ, хэш, значение); Scanandlockforput () исходный код
частное хантристское значение <K, V> ScanAndlockforput (k Key, int hash, v Значение) {Hashentry <K, v> First = intryforhash (this, hash); Хашентрит <K, v> e = первое; Hashentry <K, v> node = null; int retries = -1; // отрицательный во время поиска узла // петли, чтобы получить блокировку while (! trylock ()) {Hashentry <K, v> f; // Чтобы перепроверить сначала ниже if (retries <0) {if (e == null) {if (node == null) // Спекулятивно создавать узел // хэш -бит не имеет значения, создать новый объект и не нужно перейти к блокировке метода put () для создания нового узла = новый хэшингтри <K, v> (hash, ключ, значение, null); RETRIES = 0; } // Ключ положения хэша одинакова, дегенерирует в спин -блокировку, иначе if (key.equals (e.key)) Refries = 0; else // RESRIE могут автоматически читать связанный список в кэш E = E.Next; } // Когда повторно обрабатывает> 0, он становится спин -замком. Конечно, если количество повторений превышает MAX_SCAN_RETRIES (одноразовое 1-яловое много ядер 64), то не схватите его, введите очередь блокировки и не ожидайте, пока LOCK // LOCK () является методом блокировки, пока он не вернется после получения блокировки, в противном случае он будет зависеть иначе, если (++ retries> max_scan_retries) {lock (); перерыв; } else if ((Retries & 1) == 0 && // В настоящее время существует большая проблема, то есть новые элементы Введите связанный список и станут новым заголовком // Таким образом, стратегия здесь заключается в том, что она эквивалентна прохождению метода Scanandlockfort (f = intrintforhash (this, hash))! = First) {e = First = f; // re -traverse, если запись изменила reties = -1; }} return node;} 4 Вы можете сначала использовать его для определения равенства объекта ==
Судя о том, равны ли объекты, вы можете сначала использовать ==, потому что == напрямую сравнивать адреса, которые очень быстрые, в то время как равные сравнит наибольшее количество значений объектов, что является относительно медленным. Поэтому, если возможно, вы можете использовать A == B || A.Equals (b) сравнить, равны ли объекты.
5 о переходных
Переход используется для предотвращения сериализации, но внутренний массив в исходном коде HashMap определяется как переходная.
/*** Таблица, изменившаяся по мере необходимости. Длина всегда должна быть силой двух. */ переходная запись <K, v> [] table = (inpit <k, v> []) empty_table;
Тогда разве пары ключа внутри не могут быть сериализованы? Разве невозможно передавать использование HashMap в сети? На самом деле, это не так.
Эффективный Java 2nd, Item75, Джошуа упомянул:
Например, рассмотрим случай хэш -таблицы. Физический
Представление-это последовательность хеш-ведер, содержащие ключевую ценность
записи. Ведро, в котором находится запись, является функцией хэша
код своего ключа, который, как правило, не гарантированно будет таким же
от реализации JVM до реализации JVM. На самом деле, это даже не
Гарантированно будет то же самое от бега до бега. Поэтому принятие
сериализованная форма по умолчанию для хэш -таблицы будет представлена серьезной
ошибка. Сериализация и десериализация хэш -таблицы может дать
объект, чьи инварианты были серьезно коррумпированы.
Как понять? Взгляните на hashmap.get ()/put (), чтобы узнать, что карта чтения и записи основана на Object.hashcode (), чтобы определить, какое ведро для чтения/записи. Object.hashcode () - это собственный метод, который может отличаться в разных JVM.
Например, сохранить запись в HashMap, ключ - это строка «String». В первой Java -программе HashCode () «String» - 1, а ведро номер 1 хранится; Во второй Java -программе HashCode () «String» может быть 2, а ведро номер 2 хранится. Если используется сериализация по умолчанию (таблица Intpring [] не требует переходных процессов), то после этого HashMap импортирует вторую программу Java посредством сериализации из первой программы Java, ее распределение памяти одинаково, что неправильно.
Например, если вы сохраняете запись пары ключей в HashMap, key = "fang laosi", в первой программе Java Hashcode () «Fang laosi»-1, а таблица [1] сохраняется. Хорошо, теперь он передается в другую программу JVM, HashCode () «Fang Laosi» может быть 2, поэтому вы перейдите к таблице [2], чтобы получить его, и результат не существует.
Текущий HashMap ReadObject и writeBject используются для вывода/входного содержания и регенерации HashMap.
6 Не используйте char
Чар кодируется в UTF-16 в Java и составляет 2 байта, а 2 байта не могут представлять всех символов. 2 байта называются BMP, а другой называется высоким суррогатным и низким суррогатом, образуя 4-байтовый символ, представленное списанием. Например, индекс в строковом исходном коде:
// вот int, чтобы принять символ, чтобы облегчить суждение о диапазоне public int indexof (int ch, int fromindex) {final int max = value.length; if (fromindex <0) {fromindex = 0; } else if (fromIndex> = max) {// Примечание: fromIndex может быть близок к -1 >>> 1. возврат -1; } // В диапазоне BMP if (ch <charcy.min_supplymentary_code_point) {// Обработка большинства случаев здесь (CH является кодовой точкой BMP или a // отрицательным значением (неверная кодовая точка)) окончательный char [] value = this.value; for (int i = fromindex; i <max; i ++) {if (value [i] == ch) {return i; }} return -1; } else {// в противном случае перейдите к методу четырех-байтового суждения. }}Следовательно, char Java может представлять только частичные символы BMP в UTF16. Для частичных расширенных наборов персонажей CJK (Китай, Япония и Южная Корея) они не могут быть выражены.
Например, ЧАР не может быть представлен, за исключением части ext-A на рисунке ниже.
Кроме того, есть еще одно поговорка, что вы должны использовать Char. Не используйте строку для пароля. Строка является постоянной (то есть ее нельзя изменить после создания) и будет сохранена в постоянном пуле. Если другие процессы могут сбросить память о процессе, пароль будет просочиться, когда постоянный пул сброшен, а Char [] может написать другую информацию для изменения, что означает, что он снизит риск утечки пароля.
Но я лично думаю, что вы можете сбросить память. Может ли Char может предотвратить это? Если строка не переработана в постоянном бассейне и не читается непосредственно из постоянного бассейна другими потоками, это, вероятно, очень редко.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.