في Java، هل أحتاج إلى الإعلان عن مزامنة مجموعتي إذا كانت للقراءة فقط؟

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

سؤال

أقوم بملء مجموعة مرة واحدة عندما يبدأ تطبيق الويب J2EE الخاص بي.بعد ذلك، يمكن لعدة سلاسل رسائل الوصول إليه في نفس الوقت ولكن لقراءته فقط.

أعلم أن استخدام مجموعة متزامنة أمر إلزامي لكتابة المتوازيات ولكن هل ما زلت بحاجة إليها لقراءة المتوازيات؟

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

المحلول

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


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

class Test {
    public Test(final int a, final int b) {
        this.a = a;
        this.b = b;
    }

    public int a;
    public int b;
}

public class Main {

    public static void main(String[] args) throws Exception {
        List<Test> values = new ArrayList<Test>(2);
        values.add(new Test(1, 2));
        values.add(new Test(3, 4));

        List<Test> readOnly = Collections.unmodifiableList(values);
        for (Test t : readOnly) {
            t.a = 5;
        }

        for (Test t : values) {
            System.out.println(t.a);
        }
    }

}

هذه المخرجات:

5
5

اعتبارات مهمة من @WMR answser.

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

والسبب في ذلك هو طراز ذاكرة Java ، إذا كنت تريد معرفة المزيد ، اقرأ القسم "الرؤية" في هذا الرابط: http://gee.cs.oswego.edu/dl/cpj/jmm.html

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

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

نصائح أخرى

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

والسبب في ذلك هو نموذج ذاكرة Java، إذا كنت تريد معرفة المزيد، فاقرأ قسم "الرؤية" على هذا الرابط: http://gee.cs.oswego.edu/dl/cpj/jmm.html

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

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

في الحالة العامة، يجب عليك.وذلك لأن بعض المجموعات تغير بنيتها الداخلية أثناء القراءة.يعد LinkedHashMap الذي يستخدم ترتيب الوصول مثالًا جيدًا.لكن لا تأخذ كلامي على محمل الجد:

في خرائط التجزئة المرتبطة التي يتم طلب الوصول إليها، يعد مجرد الاستعلام عن الخريطة باستخدام get بمثابة تعديل هيكلي javadoc.javadoc لخريطة التجزئة المرتبطة

إذا كنت متأكدًا تمامًا من عدم وجود ذاكرات تخزين مؤقت، أو إحصائيات تجميع، أو تحسينات، أو أشياء مضحكة على الإطلاق - فلن تحتاج إلى المزامنة.في هذه الحالة كنت سأضع قيدًا على المجموعة:لا تعلن عن المجموعة كخريطة (والتي من شأنها أن تسمح بـ LinkedHashMap) ولكن كـ HashMap (بالنسبة للأصوليين، فئة فرعية نهائية من HashMap، ولكن هذا قد يأخذ الأمر بعيدًا جدًا ...).

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

yourCollection = Collections.unmodifableCollection(yourCollection);

(توجد طريقة مشابهة للقائمة، المجموعة، الخريطة وأنواع المجموعات الأخرى)

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

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