سؤال

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

public class Count { 
    private int count = 0; 
    public synchronized void setCount(int count) { 
        this.count = count; 
    } 
    public synchronized int getCount() { 
        return count; 
    } 
} 
class CountRunner extends Thread { 
    Count count; 
    public CountRunner(Count count) { 
        this.count = count; 
    } 
    public void run() { 
        for (int i = 1; i <= 1000; i++) { 
            count.setCount(count.getCount() + 1); 
        } 
    } 
} 
class TestCount { 
    public static void main(String[] args) throws Exception { 
        Count count = new Count(); 
        CountRunner runnerA = new CountRunner(count); 
        CountRunner runnerB = new CountRunner(count); 
        runnerA.start(); 
        runnerB.start();         
        runnerA.join(); //join statement here 
        runnerB.join(); 
        System.out.println("count.getCount = " + count.getCount()); 
    } 
} 
Question:
1. The result is a little less than 2000 for many times, why ?
2. if delete 2 join() statement, why count.getCount = 451,even less ?
3. i think there will be no effect of deleting the join() statements,
because i already have Synchronized method to lock one object to one thread each time ? 
So, What's the point of using Synchronized and join() ?
هل كانت مفيدة؟

المحلول

هو بسيط جدا.يمكنك استدعاء الأسلوب SetCount عن طريق استدعاء GetCount + 1. قبل إدخال الطريقة، يقوم وقت التشغيل بتقييم GetCont NetCount (متزامن)، لكنك لا تحتفظ بالقفل عند مغادرته GetCOUNT وإدخال SetCount وغيرها من المواضيع يمكن إدخال مكالمة GetCount.لذلك كل الآن وبعد ذلك (أو أكثر اعتمادا على عدد المواضيع التي تنشئها) الخيوط ستكون لها نفس القيمة في getcount.تخيل الموضوع يدخل ويستقبل القيمة 1 في getcount.تعطي وقت التشغيل من التنفيذ إلى Freed B الذي يستدعي GetCOUNET ويتلقى نفس القيمة 1. يربط مؤشر الترابط B القيمة إلى 1 ويجعل 50 تشغيلا آخر، لذلك سيكون عدد الخاص بك 50 في تلك المرحلة.يعطي وقت التشغيل التنفيذ إلى الخيط الذي يستدعي SetCount مع 1 (تذكر أنه لم يتمكن من الاتصال SetCount وأسفر عنه EXEC).الآن قم بتعيين القيمة إلى 1 (وهذا خطأ).

قم بتغيير تنفيذ التنفيذ مثل هذا: giveacodicetagpre.

نصائح أخرى

  1. إذا كنت كسر خط

    العد.setCount(عد.getCount() + 1);

في 3 أسطر منفصلة, انها سوف تكون أكثر وضوحا:

final int oldCount = count.getCount(); // a
final int newCount = oldCount + 1; // b
count.setCount(newCount); // c

نلاحظ أنه في حين أن بيانات (أ) و (ج) هي كل متزامنة ، كتلة كاملة هو لا.حتى أنها يمكن أن لا تزال تعشيق ، مما يعني الخيط يمكن أن تدخل/تنفيذ بيان (أ) بعد موضوع ب ينفذ الخيط (أ) ولكن قبل ينتهي/يدخل بيان (ج).عندما يحدث هذا الخيط (أ) و (ب) سوف يكون لها نفس oldCount وبالتالي يفتقد زيادة واحدة.

2.

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

3.انظر إجابة 2.

1) لأنك لا قفل بشكل صحيح.أنت تتصل getCount(), ، الذي يقفل ، يحصل على القيمة ويفتح ، يزداد ويدعو setCount() الذي يقفل ، يحفظ القيمة ويفتح.ما يحدث في بعض الحالات هو أن كلا الموضوعين يستدعيان getCount(), ، أقفال المداس الأولى ، تحصل على القيمة xويفتح.ثم يحصل الخيط الثاني على القفل ، ويحصل على نفس القيمة xويفتح .نظرا لأن كلا الخيطين يزدادان ويحفظان نفس القيمة لاحقا ، فستحصل على عدد أقل من المتوقع.

2) بدون join() لن تنتظر حتى تنتهي مؤشرات الترابط الخاصة بك ، سوف يتصل مؤشر الترابط الرئيسي الخاص بك فقط getCount() والحصول على قيمة عشوائية في حين أن المواضيع لا تزال قيد التشغيل.

3) بما أن الخيوط الأخرى لا تحمل قفلا طوال الوقت (إذا كنت تريد لهم على حد سواء على التوالي ، فإنها تحتاج إلى إعطاء كل الوقت مقفلة أخرى بعد كل شيء) ، سوف تحتاج إلى join()لا يزال.

someThread.join() سوف يسبب الدعوة Thread الانتظار حتى someThread اكتمل.

إذا قمت بإزالة join() المكالمات ، ثم الرئيسية Thread قد اتصل getCount() قبل الانتهاء من العد ، لأن someThread ربما لا يزال قيد التشغيل.

تعني الطريقة المتزامنة ببساطة أن أكثر من مكالمة متزامنة إلى ملف Object لا يمكن أن يتم في نفس الوقت.

الجواب سطر واحد هو أن count.setCount(count.getCount() + 1); ليست عملية ذرية.

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

طريقة واحدة لتجنب التهم المفقودة هي إنشاء ذرية increment() العملية.

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