هل أحتاج إلى مزامنة الطرق داخل طريقة التشغيل في Java عند استدعاء طريقة البدء؟

StackOverflow https://stackoverflow.com/questions/8351825

سؤال

هل يمكن لأحد أن يخبرني إذا كنت على حق أم لا؟لدي موضوعين سيتم تشغيلهما بالتوازي.

class MyThread extends Thread {

    MyThread() {
    }

    method1() {
    }

    method2() {
    }

    method3() {
    }

    approach(1):

        run() {
            method1();
            method2();
            method3();
        }

    approach(2):

        run() {
            //the code of method1 is here (no method calling)
            //the code of method2 is here (no method calling)
            //the code of method3 is here (no method calling)
        }

}

class Test{
    public static void main(){
        Thread t1 = new Thread();
        t1.start();
        Thread t2 = new Thread();
        t2.start();
    }
}

method1, method2 و method3 لا تصل إلى البيانات المشتركة العالمية ولكن أكوادها تقوم ببعض الكتابة في متغير محلي داخل قسم الطريقة، وبالتالي أعتقد أنني لا أستطيع السماح بالتنفيذ المتداخل داخل قسم الطريقة.

وبالتالي:في approach(1):أحتاج إلى عمل الطرق (method1, method2 و method3) متزامنة، أليس كذلك؟

في approach(2):لا حاجة لمزامنة أقسام التعليمات البرمجية، أليس كذلك؟

إذا كنت على حق في كلا النهجين، باستخدام approach(2) سوف تعطي أداء أفضل، أليس كذلك؟

هل كانت مفيدة؟

المحلول

وأنت تقول وسائل الخاص بك عدم وصول البيانات المشتركة العالمية والكتابة فقط المتغيرات المحلية لذلك ليس هناك حاجة لتزامنها لأن كلا من المواضيع سوف يكون لها نسخهم الخاصة من المتغيرات المحلية. أنها لن التداخل أو شيء من هذا.

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

نصائح أخرى

اجابة قصيرة:لا تحتاج إلى المزامنة.كلا النهجين متكافئان من منظور سلامة الخيط.

إجابة أطول:

قد يكون من المفيد الرجوع خطوة إلى الوراء وتذكر ما تفعله الكتلة المتزامنة.إنه يفعل في الأساس شيئين:

  1. يتأكد من أنه إذا كان مؤشر الترابط A موجودًا داخل كتلة متزامنة على الكائن M، فلن يتمكن أي مؤشر ترابط آخر من الدخول إلى كتلة متزامنة على نفس الكائن M حتى ينتهي مؤشر الترابط A من كتلة التعليمات البرمجية الخاصة به
  2. تأكد من أنه إذا كان مؤشر الترابط A قد قام يعمل داخل كتلة تم مزامنتها كائن M ، ثم ينتهي هذا الكتلة ، ثم يدخل الخيط B إلى كتلة تتم مزامنتها أيضًا على M ، ثم يرى الخيط B كل ما قام به الخيط A داخل متزامنه حاجز.وهذا ما يسمى تأسيس العلاقة التي تحدث قبل.

لاحظ أن الطريقة المتزامنة هي مجرد اختصار لتغليف كود الطريقة في المزامنة (هذا) { ...}.

بالإضافة إلى هذين الأمرين، يضمن نموذج ذاكرة Java (JMM) أنه خلال مؤشر ترابط واحد، ستحدث الأشياء كما لو لم يتم إعادة ترتيبها.(قد يتم إعادة ترتيبها في الواقع لأسباب مختلفة، بما في ذلك الكفاءة - ولكن ليس بطريقة يمكن لبرنامجك أن يلاحظها في سلسلة رسائل واحدة.على سبيل المثال، إذا قمت بإجراء "x = 1؛y = 2" المترجم حر في التبديل بحيث يحدث y = 2 قبل x = 1، نظرًا لأن الخيط الواحد لا يمكنه ملاحظة الفرق فعليًا.إذا كانت هناك سلاسل رسائل متعددة تصل إلى x وy، فمن الممكن جدًا، دون المزامنة المناسبة، أن يرى مؤشر ترابط آخر y = 2 قبل أن يرى x = 1.)

لذا، بالعودة إلى سؤالك الأصلي، هناك بعض الملاحظات المثيرة للاهتمام.

أولاً، نظرًا لأن الطريقة المتزامنة هي اختصار لوضع الطريقة بأكملها داخل "synchronized (this) { ...}" ، لن تتم مزامنة أساليب t1 وأساليب t2 مع نفس المرجع، وبالتالي لن تتم مزامنتها بالنسبة لبعضها البعض.ستتم مزامنة أساليب t1 فقط مع كائن t1، وستتم مزامنة أساليب t2 فقط مع كائن t2.بمعنى آخر، سيكون من الجيد تمامًا تشغيل t1.method1() وt2.method1() في نفس الوقت.لذلك، من بين هذين الأمرين اللذين توفرهما الكلمة الأساسية المتزامنة، فإن الأول (حصرية إدخال الكتلة) ليس له صلة.يمكن أن تسير الأمور على النحو التالي:

  1. يريد t1 إدخال الطريقة 1.إنه بحاجة إلى الحصول على شاشة t1، وهو أمر غير متنازع عليه - لذا فهو يحصل عليها ويدخل إلى الكتلة
  2. t2.يريد إدخال الطريقة 2.يجب عليه الحصول على الشاشة رقم 11، وهو أمر غير متنازع عليه - حيث يحصل عليها ويدخل إلى الكتلة
  3. ينهي t1 الطريقة 1 ويحرر قبضته على شاشة t1
  4. ينهي t2 الطريقة 1 ويحرر قبضته على شاشة t2

أما بالنسبة للشيء الثاني الذي تقوم به المزامنة (تحديد حدوث ما قبل)، فإن إجراء مزامنة للطريقة 1() والطريقة 2() سيضمن بشكل أساسي حدوث t1.method1() قبل t1.method2().ولكن نظرًا لأن كلا الأمرين يحدثان على نفس الخيط على أي حال (خيط t1)، فإن JMM على أي حال يضمن حدوث ذلك.

لذلك يصبح الأمر في الواقع أقبح قليلاً.إذا كان t1 وt2 يشتركان في الحالة - أي أن المزامنة ستكون ضرورية - فإن جعل الطرق متزامنة سيكون لا يكون كافيا.تذكر أن الطريقة المتزامنة تعني المزامنة (هذا) { ...}، لذا ستتم مزامنة أساليب t1 مع t1، وستكون أساليب t2 مقابل t2.في الواقع، لن تتمكن من إثبات أي حدوث قبل وجود علاقة بين أساليب t1 وt2.

وبدلاً من ذلك، يجب عليك التأكد من مزامنة الطرق على نفس المرجع.هناك طرق مختلفة للقيام بذلك، ولكن في الأساس، يجب أن يكون مرجعًا لكائن يعرفه كلا الخيطين.

افترض أن t1 وt2 يعرفان نفس المرجع، LOCK.كلاهما لديه أساليب مثل:

method1() {
    synchronized(LOCK) {
        // do whatever
    }
}

الآن يمكن أن تسير الأمور على هذا النحو:

  1. يريد t1 إدخال الطريقة 1.إنه يحتاج إلى الحصول على شاشة LOCK، وهو أمر غير متنازع عليه - لذا فهو يحصل عليه ويدخل إلى الكتلة
  2. يريد t2 إدخال الطريقة 1.يجب أن يحصل على شاشة LOCK، التي يحتفظ بها t1 بالفعل - لذلك يتم تعليق t2.
  3. ينهي t1 الطريقة 1 ويحرر قبضته على شاشة القفل
  4. أصبح t2 الآن قادرًا على الحصول على شاشة LOCK، وهو ما يفعل ذلك ويبدأ في لحم الطريقة 1
  5. ينتهي t2 من الطريقة 1 ويحرر قبضته على شاشة LOCK

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

في برنامج مؤشرات، كل موضوع له مكدس الاستدعاءات الخاصة بها. سوف المتغيرات المحلية لكل طريقة تكون منفصلة في كل موضوع، وسوف لا الكتابة فوق بعضها البعض.

لذلك، نهج 1 يعمل على ما يرام، لا تتطلب النفقات العامة التزامن، وأفضل بكثير البرمجة الممارسة لأنها تتجنب تكرار الكود.

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

وأنت لن يكون أي تحسينات في السرعة بين اثنين من يقترب منه هو مجرد تنظيم أفضل من قانون (طرق أقصر وأسهل للفهم)

إذا كل طريقة مستقلة عن الأخرى التي قد ترغب في النظر إذا كانوا ينتمون في نفس الفئة. إذا كنت ترغب في كسب الأداء خلق 3 فئات مختلفة وتنفيذ المواضيع متعددة لكل طريقة (المكاسب الأداء يعتمد على عدد المتوفرة وحدة المعالجة المركزية النوى / الإعلام والتوعية التموينية الخ.)

<اقتباس فقرة>

وبالتالي: في نهج (1): لست بحاجة لجعل الطرق (method1، method2 وmethod3) متزامنة، أليس كذلك؟ في النهج (2): لا حاجة ل مزامنة فروع القانون، أليس كذلك؟

وأساليب الاحتجاج واصطف في الخامس / ق استدعاء أساليب متعددة لا تحدد ما إذا كان الأسلوب يجب أن تكون متزامنة أم لا. انصح لك قراءة هذا ثم نطلب أكثر توضيحات.

<اقتباس فقرة>

إذا أنا على حق في كل نهج، وذلك باستخدام نهج (2) سوف تعطي أداء أفضل، أليس كذلك؟

وعلى حساب تحطيم الطرق إلى أسلوب إله واحد؟ بالتأكيد، ولكن لك أن تبحث في تحسن "جدا" ضئيلة بالمقارنة مع قراءة كود المفقودة، وهو أمر بالتأكيد غير مستحسن.

وmethod1 و 2 و 3 لن يتم تنفيذ في وقت واحد حتى إذا المتغيرات التي كانت قراءة / الكتابة ليست مشتركة خارج الصف مع المواضيع الأخرى في حين أنها تقوم بتشغيل ثم ليست هناك تزامن المطلوبة وهناك حاجة لالمضمنة.

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

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

وإذا كان من المتوقع لقراءة البيانات المعدلة عن طريق method1 أو 2 أو 3 المواضيع الأخرى، ثم تحتاج إلى إجراء مزامنة طريقة تشغيل (أو هم في كتلة متزامنة) لاقامة بوابة بحيث JVM ستنشئ تتم الذاكرة حاجز والتأكد من أن المواضيع الأخرى يمكن أن يرى البيانات بعد m1،2 و 3.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top