لم تعد خائفة من المحاور ، اضغط على نقطة الألم لفهم الكلمة الأساسية المتقلبة ، دع المقابلة تمر بسهولة

مقدمة

مع صعود شركات الإنترنت ، أصبحت متطلبات التكنولوجيا لدينا أعلى وأعلى. وفي كثير من الحالات ، ترغب الشركات في توفير المال وتعظيم أداء الماكينة ، الأمر الذي يرهق المبرمجين حقًا.

بالطبع ، من أجل التكيف مع تقدم المجتمع ، يجب على المبرمجين إعادة شحن أنفسهم باستمرار ، ولكن يمكن للناس أن ينسوا أساسياتهم ، ولا تزال المعرفة الأساسية بحاجة إلى التعلم.

لا ، لقد جاء إلي أحد زملائي في الدراسة واشتكى ، وكانت المقابلتان الأوليتان سلسة للغاية ، وعلى الجانبين الثلاثة ، زرعت على الكلمة الأساسية المتقلبة.

دعنا نتحدث عن متقلب

متطايره

متقلب هو نوع تعديل. دور المتغير هو أن تكون بمثابة كلمة أساسية للتعليمات لضمان عدم حذف هذه التعليمات بسبب تحسين المترجم

ميزات متقلبة

  • وهذا يضمن رؤية سلاسل الرسائل المختلفة التي تعمل على هذا المتغير ، أي أن مؤشر ترابط واحد يعدل قيمة المتغير ، وتكون القيمة الجديدة مرئية على الفور لمؤشرات الترابط الأخرى. (تحقيق الرؤية)
  • يحظر إعادة ترتيب التعليمات. (تحقيق الطلب)
  • المتطاير يمكن أن يضمن فقط الذرية لقراءة / كتابة واحدة. i ++ هذه العملية لا يمكن أن تضمن الذرية.

يمكن فهم الذرية المتطايرة على أنها قراءة / كتابة واحدة للمتغيرات المتغيرة ، والتي تعتبر بمثابة استخدام نفس القفل لمزامنة عمليات القراءة / الكتابة الفردية ، والتي تشبه وظائف SoWhat و SynSoWhat التالية.

class SoWhat {ما الذي { متغير int i = 0 ؛ // متغير معدل متغير public int getI () { return i؛ // قراءة متغير متغير واحد }} setI void public (int j) { this.i = j؛ // اكتب متغير متغير واحد }} public void inc () { i ++ ؛ // متغيرات متعددة متقلبة مركبة }} }} الفئة SynSoWhat { int i = 0 ؛ int getI المتزامن العام () { العودة i ؛ }} مجموعة الفراغ المتزامنة العامة (int j) { this.i = j ؛ }} public void inc () {/ / call method int tmp = getI ()؛ // استدعاء الأسلوب المتزامن tmp = tmp + 1 ؛ // طريقة الكتابة العادية setI (tmp)؛ // استدعاء الطريقة المتزامنة }} }}

اكتب الفهم

دلالات الذاكرة التي كتبها متطايرة هي كما يلي:

عند كتابة متغير متغير ، سوف تقوم JMM بتحديث قيمة المتغير المشترك في اللغة المحلية المقابلة لمؤشر الترابط إلى الذاكرة الرئيسية.

الطبقة العامة VolaSemanteme { int a = 0 ؛ علم منطقي متطاير = خطأ ؛ // هذه هي النقطة الحرف الأول الفراغ () { أ = 1 ؛ العلم = صحيح ؛ // ....... }} استخدام الفراغ العام () { if (flag) { int i = a * a ؛ }} // ....... }} }}

مؤشر الترابط A يستدعي أسلوب التهيئة ، ويتصل مؤشر الترابط B طريقة الاستخدام.

قراءة الفهم

دلالات ذاكرة القراءة المتطايرة هي كما يلي:

عند قراءة متغير متغير ، ستبطل JMM الذاكرة المحلية المقابلة لمؤشر الترابط. سيقرأ الخيط بعد ذلك المتغير المشترك من الذاكرة الرئيسية.

الطبقة العامة VolaSemanteme {

int a = 0 ؛

علم منطقي متطاير = خطأ ؛ // هذه هي النقطة

الحرف الأول الفراغ () {

أ = 1 ؛

العلم = صحيح ؛

// .......

}}

استخدام الفراغ العام () {

if (flag) {

int i = a * a ؛

}}

// .......

}}

}}

المخطط الانسيابي هو تقريبًا هذا:

إعادة ترتيب التعليمات المتطايرة

تعتمد رؤية الذاكرة للمتغيرات المتغيرة على حاجز الذاكرة. لم يتم تكرار التفسير الخاص حول حاجز الذاكرة من قبل ، وأجبرت معدات JMM على أن تكون غير مرئية هنا. باختصار ، سيكون هناك إعادة ترتيب التعليمات داخل JMM ، وسوف يكون هناك مفاهيم af-if-serial و قبل حدوثها لضمان صحة إعادة ترتيب التعليمات. يعتمد حاجز الذاكرة على أربع كلمات رئيسية على مستوى التجميع لمنع إعادة ترتيب التعليمات ، من بينها قواعد إعادة الترتيب المتغيرة كما يلي:

  • عندما تكون الأولى عملية قراءة ، لا يمكن إعادة ترتيب أي عملية ثانية قبل الأولى.
  • عندما تكون الثانية عملية كتابة ، لا يمكن إعادة ترتيب أي عملية من العمليات الأولى بعد الثانية.
  • عندما تكون العملية الأولى عبارة عن عملية كتابة ، فإن عملية القراءة والكتابة الثانية لا تقوم أيضًا بإعادة الترتيب.

متقلب كتابة التنفيذ الأساسي

استراتيجية الإدراج JMM لحاجز الذاكرة المتقلبة

أدخل حاجز StoreStore أمام كل عملية كتابة متقلبة. قم بإدراج حاجز StoreLoad بعد كل عملية كتابة متقلبة.

متقرا قراءة التنفيذ الأساسي

استراتيجية الإدراج JMM لحاجز الذاكرة المتقلبة

أدخل حاجز LoadLoad بعد كل عملية قراءة متقلبة. أدخل حاجز LoadStore بعد كل عملية قراءة متقلبة.

النقطة الأساسية هي لماذا يتبع القراءة المتغيرة التالية LoadLoad. انضم إليّ باستخدام الكود التالي AB تنفيذ موضوعين ، علم مؤشر الترابط B يحصل على القراءة التالية مسبقًا.

مبدأ التنفيذ المتطاير

عند كتابة متغير مشترك مزين بمتغير متغير ، يتم استخدام تعليمات بادئة القفل المقدمة من وحدة المعالجة المركزية. الوظائف على مستوى وحدة المعالجة المركزية هي كما يلي:

أعد كتابة بيانات ذاكرة التخزين المؤقت للمعالج الحالي في ذاكرة النظام

ستخبرك عملية إعادة الكتابة إلى الذاكرة بأن المتغيرات التي تحصل عليها في وحدات المعالجة المركزية الأخرى غير صالحة وستحتاج إلى إعادة مشاركة الذاكرة عند استخدامها في المرة التالية.

يمكننا أخذ تفكيك مفصل للرمز البسيط من خلال jitwatch.

حزمة com.sowhat.demo ؛ الطبقة العامة VolaSemanteme { int unvloatileVal = 0 ؛ علم منطقي متطاير = خطأ ؛ الحرف الأول الفراغ () { unvloatileVal = 1 ؛ العلم = صحيح ؛ // السطر 9 }} استخدام الفراغ العام () { if (flag) { int LocalA = unvloatileVal؛ إذا (LocalA == 0) { رمي RuntimeException جديدة ("خطأ") ؛ }} }} }} الفراغ الثابت العام الرئيسي (سلسلة السلاسل) { VolaSemanteme volaSemanteme = جديد VolaSemanteme () ؛ volaSemanteme.init () ؛ volaSemanteme.use () ؛ }} }}

تعيين المتغيرات العادية:

عمليات التعيين للمتغيرات المتغيرة.

يمكن مقارنة أن المتغير الذي تم تعديله بواسطة المتغير سيكون لديه بالفعل قفل إضافي addl $ 0x0 ، ( rsp).

0x0000000114ce95cb: قفل addl $ 0x0 ، ( rsp) ؛ * علامة putfield ؛ -com.sowhat.demo.VolaSemanteme :: init @ 7 (السطر 9)

سيناريوهات التطبيق المتقلبة

متطلبات استخدام متقلبة

  • لا تعتمد الكتابة على المتغيرات على القيمة الحالية.
  • لا يتم تضمين هذا المتغير في المتغير مع المتغيرات الأخرى.

يمكنك استخدام متقلب فقط إذا كانت الدولة مستقلة حقًا عن بقية البرنامج.

علم الحالة

ربما يكون الاستخدام المتعارف عليه لتطبيق المتغيرات المتغيرة هو ببساطة استخدام علامة الحالة المنطقية للإشارة إلى حدوث حدث هام لمرة واحدة ، مثل إكمال التهيئة أو طلب إيقاف التشغيل.

إغلاق منطقي متقلب ... اغلاق الفراغ العام () {shutdownRequested = true؛} doWork العامة () { بينما (! shutdownRequested) { // افعل اشياء }} }}

منشور آمن لمرة واحدة

إن عدم وجود التزامن يجعل من المستحيل تحقيق الرؤية ، مما يجعل من الصعب تحديد وقت كتابة مرجع كائن بدلاً من القيمة الأصلية. في غياب المزامنة ، قد تصادف وجود القيمة المحدثة التي تمت الإشارة إليها بواسطة كائن (مكتوب بواسطة مؤشر ترابط آخر) والقيمة القديمة لحالة الكائن موجودة في نفس الوقت. (هذا هو السبب الجذري لمشكلة القفل المزدوج للتحقق الشهيرة ، حيث تتم قراءة مراجع الكائن بدون مزامنة. المشكلة هي أنه قد ترى مرجعًا محدثًا ، ولكن لا يزال انظر الكائن الذي تم بناؤه بشكل غير كامل من خلال هذا المرجع).

فئة عامة BackgroundFloobleLoader { الجمهور المتطاير Flooble theFlooble ؛ initInBackground () {العامة فارغة) { // قم بالكثير من الأشياء theFlooble = new Flooble ()؛ // هذه هي الكتابة الوحيدة إلى Floboble }} }} فئة عامة SomeOtherClass { doWork العامة () { احيانا صحيح) { // قم ببعض الأشياء ... // استخدم Flooble ، ولكن فقط إذا كان جاهزًا if (floobleLoader.theFlooble! = null) doSomething (floobleLoader.theFlooble) ؛ }} }} }}

ملاحظة مستقلة

طريقة أخرى بسيطة لاستخدام المتطايرة بأمان هي نشر نتائج المراقبة بشكل دوري للاستخدام الداخلي في البرنامج. على سبيل المثال ، لنفترض أن هناك مستشعرًا بيئيًا يمكنه استشعار درجة الحرارة المحيطة. قد يقرأ مؤشر ترابط الخلفية المستشعر كل بضع ثوانٍ ويحدث المتغير المتغير الذي يحتوي على المستند الحالي. بعد ذلك ، يمكن لمؤشرات الترابط الأخرى قراءة هذا المتغير حتى يتمكنوا من رؤية أحدث قيمة لدرجة الحرارة في أي وقت.

UserManager الطبقة العامة { سلسلة متغيرة عامة lastUser ؛ المصادقة المنطقية العامة (مستخدم السلسلة ، سلسلة كلمة المرور) { قيمة منطقية = passwordIsValid (المستخدم ، كلمة المرور) ؛ إذا (صالح) { User u = مستخدم جديد () ؛ activeUsers.add (u) ؛ lastUser = المستخدم ؛ }} عودة صالحة ؛ }} }}

نمط الفول المتطاير

في وضع الفول المتطاير ، يكون جميع أعضاء البيانات في JavaBean من النوع المتغير ، ويجب أن تكون طرق getter و setter شائعة جدًا - بالإضافة إلى الحصول على أو تعيين الخصائص المقابلة ، لا يمكن أن تحتوي على أي منطق. بالإضافة إلى ذلك ، بالنسبة لأعضاء البيانات المشار إليها بواسطة الكائن ، يجب أن يكون الكائن المشار إليه غير قابل للتغيير بشكل فعال. (سيؤدي هذا إلى منع السمات ذات قيم الصفيف ، لأنه عندما يتم الإعلان عن مرجع الصفيف على أنه متغير ، فإن المرجع فقط ، وليس الصفيف نفسه ، له دلالات متغيرة). بالنسبة لأي متغير متغير ، لا يمكن أن تحتوي الثوابت أو القيود على سمات JavaBean.

ThreadSafe شخص الطبقة العامة { سلسلة المتغيرة الخاصة firstName ؛ سلسلة المتغيرة الخاصة lastName ؛ سن int تقلبات خاصة. السلسلة العامة getFirstName () {return firstName؛} السلسلة العامة getLastName () {return lastName؛} public int getAge () {سن العودة ؛} مجموعة الفراغ العامة (الاسم الأول للسلسلة) { this.firstName = firstName ؛ }} setLastName الفراغ العام (String lastName) { this.lastName = lastName ؛ }} مجموعة الفراغ العامة (العمر الصحيح) { this.age = العمر ؛ }} }}

استراتيجية قفل القراءة والكتابة منخفضة التكلفة

وظيفة المتطاير ليست كافية لتنفيذ عداد. لأن ++ x هو في الواقع مزيج بسيط من ثلاث عمليات (قراءة ، إضافة ، تخزين) ، إذا حدث أن حاولت عدة سلاسل تنفيذ عمليات إضافية على العداد المتغير في نفس الوقت ، فقد تفقد قيمته المحدثة. إذا تجاوزت عملية القراءة بكثير عملية الكتابة ، يمكنك استخدام مجموعة من الأقفال الداخلية والمتغيرات المتغيرة لتقليل الحمل الزائد لمسار الرمز الشائع. تستخدم العدادات الآمنة بشكل متزامن لضمان أن تكون العمليات الإضافية ذرية ، وتستخدم متقلبة لضمان رؤية النتيجة الحالية. إذا لم يكن التحديث متكررًا ، يمكن أن تحقق هذه الطريقة أداءً أفضل ، لأن تكلفة مسار القراءة تنطوي فقط على عمليات قراءة متغيرة ، والتي عادة ما تكون أفضل من تكلفة الحصول على قفل بدون منافسة.

ThreadSafe الطبقة العامة CheesyCounter { // يستخدم خدعة قفل القراءة والكتابة الرخيصة // يجب أن تتم جميع العمليات الطفرية مع قفل "هذا" GuardedBy ("this") قيمة int المتطايرة الخاصة ؛ public int getValue () {return value؛} الزيادة العامة المتزامنة العامة () { إرجاع القيمة ++ ؛ }} }}

فحص مزدوج

طريقة لتحقيق وضع المفرد ، لكن الكثير من الناس سيتجاهلون الكلمة الأساسية المتغيرة ، لأنه بدون هذه الكلمة الرئيسية ، يمكن للبرنامج أن يعمل بشكل جيد للغاية ، لكن استقرار الشفرة ليس دائمًا 100 في تلك اللحظة ، خرج الخطأ الخفي.

class سينجلتون { مثيل Singleton الثابت المتطاير الخاص ؛ سينجليتون العامة الثابتة getInstance () { إذا (المثال == فارغ) { syschronized (Singleton.class) { إذا (المثال == فارغ) { سبيل المثال = جديد Singleton () ؛ }} }} }} مثيل العودة ؛ }} }}

يوصي التحميل البطيء بالكتابة الأنيقة التهيئة على حامل الطلب (IODH).

فئة عامة Singleton { فئة ثابتة SingletonHolder { مثيل Singleton الثابت = Singleton () جديد ؛ }} سينجليتون العامة الثابتة getInstance () { إرجاع SingletonHolder.instance ؛ }} }}

هل تريد أن تعرف جدك، JRE، JVM هل هناك أي ارتباط بينها وبين ما هو؟

المبرمج: لقد كنت أفكر مؤخرًا في المفاضلة بين سلامة الخيط والأداء

المشاركة المتقدمة: هل تفهم حقًا خاصية Java multithreading؟ يأخذك للعب متعدد الخيوط مرة واحدة!

وقال زملاء المتزامنة الصعب سيكه جافا التزامن؟ ثلاثة مبادئ آليات التوافق الكامنة وراء تنفيذ

المبرمج: مزامنة موارد مشتركة متعددة الخيوط ، ستندم عليها إذا لم تأخذها على محمل الجد

مبرمج: لا تعرف كيف توقف الخيط بشكل صحيح؟

مشاركة جيدة للمقالات: 5 صور تأخذك لفهم تسجيل دخول المسؤول و CURD للمعلومات في JavaWeb

المبرمج: 5 أشياء تموت من أجل Java تم كشف النقاب عنها في قلب الكائن

الصين تدفقت مرة أخرى العلوم والتكنولوجيا والكم انفراج في القيود تكنولوجيا رقاقة، الرائدة في العالم قاب قوسين أو أدنى!

خذ الطباعة الحجرية تغيير الأقنعة! هولندا لمساعدة باء هارب، روسيا: بشرت الصين في فرصة عظيمة

معجبا! الصين تطويرها بشكل مستقل "رقاقة الكم"، لن تكون محدودة المستقبل

في أعقاب عملية الإنتاج 14nm كتلة، الصين تدفقت مرة أخرى رقائق، والاختناقات التكنولوجية لكسر الجليد 6nm