مقدمة
هذا خامل تمامًا خلال هذه الفترة ، لذلك نظرت إلى رمز مصدر JDK. يمكن لمهندس التطوير العليا العام تحسين نفسه من خلال قراءة بعض كود المصدر. تلخص هذه المقالة بعض "النصائح الصغيرة" في رمز مصدر JDK وتشاركها للرجوع إليها وتعلمك. لن أقول الكثير أدناه ، دعنا نلقي نظرة على المقدمة التفصيلية معًا.
1 i ++ vs i--
السطر 985 من رمز مصدر السلسلة ، بطريقة متساوية
بينما (n-! = 0) {if (v1 [i]! = v2 [i]) return false ؛ i ++ ؛ }يتم استخدام هذا الرمز للحكم على ما إذا كانت السلسلة متساوية ، ولكن هناك شيء غريب يستخدم I-! = 0 لإصدار أحكام. ألا نستخدم عادة i ++؟ لماذا تستخدم أنا--؟ وعدد الدورات هو نفسه. والسبب هو أنه سيكون هناك تعليمات أخرى بعد التجميع:
أنا- ستؤثر العملية نفسها على CPSR (سجل حالة البرنامج الحالي). الأعلام الشائعة لـ CPSR هي N (النتيجة سلبية) ، z (النتيجة هي 0) ، C (Carry) ، و 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 ، فإن تشغيل قطاع القفل ممتع للغاية. إنه ليس قفلًا مباشرًا ، ولكنه يشبه قفل الدوران. يحاول مرارا وتكرار الحصول على القفل. أثناء عملية الحصول على القفل ، سوف يعبر القائمة المرتبطة ، بحيث يتم تحميل البيانات في ذاكرة التخزين المؤقت للتسجيل أولاً ، وتجنب الراحة في عملية القفل. في الوقت نفسه ، يتم وضع تشغيل كائنات جديدة أيضًا خارج القفل لتجنب عمليات المستهلكة للوقت في القفل
PUT FIND V (مفتاح k ، التجزئة int ، v ، valean omsifabsent) { /** قبل الكتابة إلى هذا القطاع ، تحتاج إلى الحصول على القفل الحصري للجزء أولاً. ليس إجبار القفل () ، ولكن لمحاولة*/ hashentry <k ، v> node = trylock ()؟ NULL: SCANANDLOCKForput (المفتاح ، التجزئة ، القيمة) ؛ ScanAndlockForput () رمز المصدر
التجزئة الخاصة <k ، v> scanandlockforput (k key ، int hash ، v value) {hashentry <k ، v> first = entryforhash (this ، hash) ؛ hashentry <k ، v> e = first ؛ hashentry <k ، v> node = null ؛ int recepties = -1 ؛ // سالبة أثناء تحديد موقع العقدة // looping للحصول على القفل بينما (! trylock ()) {hashentry <k ، v> f ؛ // لإعادة الفحص أولاً أدناه إذا (Retries <0) {if (e == null) {if (node == null) // إنشاء عقدة // bit hash ليس له قيمة ، إنشاء كائن جديد ، ولا داعي للانتقال إلى قفل طريقة pum () لإنشاء عقدة جديدة = new hentry <k ، v> (hash ، value ، إعادة المحاولة = 0 ؛ } // مفتاح موضع التجزئة هو نفسه ، يتدهور إلى قفل تدور آخر إذا كان (key.equals (e.key)) يعيد استخدامه = 0 ؛ آخر // يمكن لإعادة المحاكاة قراءة القائمة المرتبطة تلقائيًا في ذاكرة التخزين المؤقت e = e.next ؛ } // عند إعادة المحاولة> 0 ، يصبح قفل تدور. بالطبع ، إذا كان عدد عمليات إعادة المحاكاة يتجاوز max_scan_retries (Core 1 multi-core 64) ، فلا تخطفه ، فأدخل قائمة انتظار الحظر وانتظر القفل // القفل () طريقة الحظر حتى يعود بعد الحصول على القفل ، وإلا فإنه سيتم تعليقه إذا (++ إعادة reclists> max_scan_scan_retries) { استراحة؛ } آخر إذا ((Retries & 1) == 0 && // هناك مشكلة كبيرة في هذا الوقت ، أي أن العناصر الجديدة تدخل في القائمة المرتبطة وتصبح رأسًا جديدًا // وبالتالي فإن الإستراتيجية هنا هي أنها تعادل المرور عبر طريقة ScanAndlockForput مرة أخرى (F = Entringforhash (هذا ،))! // re -traverse إذا تم تغيير إعادة الإدخال = -1 ؛ }} return node ؛} 4 يمكنك استخدامه أولاً لتحديد مساواة الكائن ==
عند الحكم على ما إذا كانت الكائنات متساوية ، يمكنك استخدام == أولاً ، لأن == قم بمقارنة العناوين مباشرة ، وهي سريعة جدًا ، في حين أن المساواة ستقارن أكثر قيم الكائنات ، والتي تكون بطيئة نسبيًا. لذا ، إذا كان ذلك ممكنًا ، يمكنك استخدام A == B || أ. المساواة (ب) لمقارنة ما إذا كانت الكائنات متساوية.
5 عن عابرة
يتم استخدام عابرة لمنع التسلسل ، ولكن يتم تعريف الصفيف الداخلي في رمز مصدر HASHMAP على أنه عابر.
/*** الجدول ، تغيير حجمه حسب الضرورة. يجب أن يكون الطول دائمًا قوة اثنين. */ إدخال عابر <k ، v> [] table = (إدخال <k ، v> []) فارغة _table ؛
ثم ألا يمكن تسلسل أزواج القيمة الرئيسية في الداخل؟ أليس من المستحيل إرسالها باستخدام hashmap على الشبكة؟ في الواقع ، ليس كذلك.
java 2nd 2nd ، item75 ، joshua ذكر:
على سبيل المثال ، ضع في اعتبارك حالة جدول التجزئة. المادية
التمثيل هو سلسلة من دلاء التجزئة التي تحتوي على قيمة رئيسية
إدخالات. الدلو الذي يتواجد فيه الإدخال هو وظيفة التجزئة
رمز مفتاحه ، وهو ليس ، بشكل عام ، مضمون ليكون هو نفسه
من تنفيذ JVM إلى تنفيذ JVM. في الواقع ، ليس حتى
مضمونة لتكون هي نفسها من الركض إلى الجري. لذلك ، قبول
يشكل النموذج التسلسلي الافتراضي لجدول التجزئة خطيرًا
حشرة. يمكن أن تسفر تسلسل الجدول التجزوي وإلغاء تسلسله
كائن الذين كانت ثباتهم فاسدين بشكل خطير.
كيف تفهم؟ ألقِ نظرة على hashmap.get ()/put () لمعرفة أن خريطة القراءة والكتابة تعتمد على object.hashCode () لتحديد الدلو الذي يجب قراءة/الكتابة من. Object.HashCode () هي طريقة أصلية ، والتي قد تكون مختلفة في JVMs مختلفة.
على سبيل المثال ، احفظ إدخالًا إلى HashMap ، والمفتاح هو سلسلة "السلسلة". في برنامج Java الأول ، يكون HashCode () من "السلسلة" 1 ، ويتم تخزين الرقم 1 الدلو ؛ في برنامج Java الثاني ، قد يكون hashcode () من "السلسلة" 2 ، ويتم تخزين الرقم 2 دلو. إذا تم استخدام التسلسل الافتراضي (لا يتطلب جدول الإدخال [] عابرة) ، فبعد هذا يستورد برنامج HashMap برنامج Java الثاني من خلال التسلسل من برنامج Java الأول ، فإن توزيع الذاكرة هو نفسه ، وهو أمر خاطئ.
على سبيل المثال ، إذا قمت بحفظ إدخال زوج القيمة الرئيسي إلى HashMap ، Key = "Fang Laosi" ، في برنامج Java الأول ، يتم تخزين Hashcode () من "Fang Laosi" 1 ، ويتم تخزين الجدول [1]. حسنًا ، يتم تمريره الآن إلى برنامج JVM آخر ، وقد يكون Hashcode () من "Fang Laosi" 2 ، لذلك تذهب إلى الجدول [2] للحصول عليه ، والنتيجة غير موجودة.
يتم استخدام readobject الحالي والكتابة في HashMap لإخراج/إدخال محتوى وتجديد hashmap.
6 لا تستخدم شار
يتم ترميز char في UTF-16 في Java ، وهو 2 بايت ، ولا يمكن أن يمثل 2 بايت جميع الأحرف. تسمى البايت 2 BMP ، والآخر يسمى بديل عالي وبديل منخفض لتكوين حرف 4 بايت يمثله الخبز. على سبيل المثال ، indexof في رمز مصدر السلسلة:
// فيما يلي int لقبول char لتسهيل الحكم على مجموعة int int public (int ch ، int fromindex) {final int max = value.length ؛ if (fromIndex <0) {fromIndex = 0 ؛ } آخر إذا (fromIndex> = max) {// ملاحظة: قد يكون FromIndex بالقرب من -1 >>> 1. العودة -1 ؛ } // في نطاق BMP if (ch <forme.min_supplementary_code_point) {// التعامل مع معظم الحالات هنا (CH هي نقطة رمز BMP أو القيمة السالبة (نقطة رمز غير صالحة)) Value []] value = this.value ؛ لـ (int i = fromIndex ؛ i <max ؛ i ++) {if (value [i] == ch) {return i ؛ }} return -1 ؛ } آخر {// على خلاف ذلك ، انتقل إلى طريقة الإرجاع الأربعة بايت ، INDEXOFSUPPEMENTARY (CH ، FromIndex) ؛ }}لذلك ، يمكن لـ Java's Char تمثيل الأحرف الجزئية BMP فقط في UTF16. بالنسبة لمجموعات الأحرف الممتدة الجزئية CJK (الصين واليابان وكوريا الجنوبية) ، لا يمكن التعبير عنها.
على سبيل المثال ، لا يمكن تمثيل char باستثناء الجزء Ext-A في الشكل أدناه.
بالإضافة إلى ذلك ، هناك قول آخر أنه يجب عليك استخدام char. لا تستخدم سلسلة لكلمة المرور. السلسلة ثابتة (أي ، لا يمكن تغييرها بعد الإنشاء) ، وسيتم حفظها في التجمع الثابت. إذا كانت عمليات أخرى يمكنها تفريغ ذاكرة العملية ، فسيتم تسرب كلمة المرور حيث يتم إلقاء التجمع الثابت ، ويمكن لـ Char [] كتابة معلومات أخرى للتغيير ، مما يعني أنه سيقلل من خطر تسريب كلمة المرور.
لكنني شخصياً أعتقد أنه يمكنك تفريغ الذاكرة. هل يمكن أن يكون الشار قادرًا على منعه؟ ما لم تتم إعادة تدوير السلسلة في البركة الثابتة ويتم قراءتها مباشرة من التجمع الثابت بواسطة مؤشرات ترابط أخرى ، فمن المحتمل أن تكون نادرة جدًا.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.