JavaRush /مدونة جافا /Random-AR /المستوى 26. إجابات لأسئلة المقابلة حول موضوع المستوى. الج...
zor07
مستوى
Санкт-Петербург

المستوى 26. إجابات لأسئلة المقابلة حول موضوع المستوى. الجزء 2. الأسئلة 6-9، 11-12

نشرت في المجموعة
المستوى 26. إجابات لأسئلة المقابلة حول موضوع المستوى.  الجزء الثاني. الأسئلة 6-9، 11-12-1

6. ما هو كانكارينزي؟

التزامن عبارة عن مكتبة فئات في Java تحتوي على فئات خاصة محسنة للعمل عبر سلاسل رسائل متعددة. يتم جمع هذه الفئات في حزمة java.util.concurrent. ويمكن تقسيمها تخطيطيًا وفقًا للوظيفة على النحو التالي: المستوى 26. إجابات لأسئلة المقابلة حول موضوع المستوى.  الجزء 2. الأسئلة 6-9، 11-12-2المجموعات المتزامنة - مجموعة من المجموعات التي تعمل بكفاءة أكبر في بيئة متعددة الخيوط مقارنة بالمجموعات العالمية القياسية من java.utilالحزمة. بدلاً من الغلاف الأساسي Collections.synchronizedListالذي يمنع الوصول إلى المجموعة بأكملها، يتم استخدام أقفال على قطاعات البيانات، أو يتم تحسين العمل للقراءة المتوازية للبيانات باستخدام خوارزميات خالية من الانتظار. قوائم الانتظار - قوائم الانتظار غير المحظورة والمحظورة مع دعم متعدد الخيوط. تم تصميم قوائم الانتظار غير المحظورة للسرعة والتشغيل دون حظر المواضيع. يتم استخدام قوائم الانتظار المحظورة عندما تحتاج إلى "إبطاء" سلاسل العمليات "المنتج" أو "المستهلك" إذا لم يتم استيفاء بعض الشروط، على سبيل المثال، أن تكون قائمة الانتظار فارغة أو مكتظة، أو لا يوجد "مستهلك" مجاني. المزامنات هي أدوات مساعدة لمزامنة المواضيع. إنها سلاح قوي في الحوسبة "المتوازية". المنفذون - يحتوي على أطر عمل ممتازة لإنشاء تجمعات مؤشرات الترابط وجدولة المهام غير المتزامنة والحصول على النتائج. الأقفال - تمثل آليات مزامنة خيط بديلة وأكثر مرونة مقارنة synchronizedبالآليات waitالأساسية notify. Atomics - فئات تدعم العمليات الذرية على البدائيات والمراجع. مصدر:notifyAll

7. ما هي الفصول التي تعرفها من كانكارينسي؟

الجواب على هذا السؤال مذكور تماما في هذه المقالة . لا أرى أي فائدة من إعادة طبع كل هذا هنا، لذلك سأقدم وصفًا فقط لتلك الفئات التي كان لي شرف التعرف عليها لفترة وجيزة. ConcurrentHashMap<K, V> - على عكس Hashtableالكتل synhronizedالموجودة HashMap، يتم تقديم البيانات في شكل مقاطع، مقسمة إلى تجزئات للمفاتيح. ونتيجة لذلك، يتم الوصول إلى البيانات عن طريق المقاطع وليس عن طريق كائن واحد. بالإضافة إلى ذلك، تمثل التكرارات بيانات لفترة زمنية محددة ولا ترمي ConcurrentModificationException. AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray - ماذا لو كنت في الفصل الدراسي تحتاج إلى مزامنة الوصول إلى متغير واحد بسيط من النوع int؟ يمكنك استخدام التركيبات مع ، synchronizedوعند استخدام العمليات الذرية set/get،. volatileولكن يمكنك أن تفعل ما هو أفضل باستخدام فئات جديدة Atomic*. نظرًا لاستخدام CAS، تكون العمليات مع هذه الفئات أسرع مما لو تمت مزامنتها عبر synchronized/volatile. بالإضافة إلى ذلك، هناك طرق للإضافة الذرية بمقدار معين، وكذلك الزيادة/النقصان.

8. كيف تعمل فئة ConcurrentHashMap؟

بحلول وقت تقديمها، ConcurrentHashMapكان مطورو Java بحاجة إلى تنفيذ خريطة التجزئة التالية:
  • سلامة الخيط
  • لا توجد أقفال على الجدول بأكمله أثناء الوصول إليه
  • من المستحسن عدم وجود أقفال للجدول عند إجراء عملية القراءة
أفكار التنفيذ الرئيسية ConcurrentHashMapهي كما يلي:
  1. عناصر الخريطة

    على عكس العناصر HashMap، يتم الإعلان عن Entryin كـ . هذه ميزة مهمة أيضًا بسبب التغييرات في JMM .ConcurrentHashMapvolatile

    static final class HashEntry<K, V> {
        final K key;
        final int hash;
        volatile V value;
        final HashEntry<K, V> next;
    
        HashEntry(K key, int hash, HashEntry<K, V> next, V value) {
            this .key = key;
            this .hash = hash;
            this .next = next;
            this .value = value;
         }
    
        @SuppressWarnings("unchecked")
        static final <K, V> HashEntry<K, V>[] newArray(int i) {
            return new HashEntry[i];
        }
    }
  2. دالة تجزئة

    ConcurrentHashMapيتم أيضًا استخدام وظيفة التجزئة المحسنة.

    دعني أذكرك كيف كان الأمر في HashMapJDK 1.2:

    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    الإصدار من ConcurrentHashMap JDK 1.5:

    private static int hash(int h) {
        h += (h << 15) ^ 0xffffcd7d;
        h ^= (h >>> 10);
        h += (h << 3);
        h ^= (h >>> 6);
        h += (h << 2) + (h << 14);
        return h ^ (h >>> 16);
    }

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

  3. شرائح

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

  4. مستوى التزامن

    تؤثر هذه المعلمة على استخدام بطاقة الذاكرة وعدد المقاطع الموجودة في البطاقة.

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

  5. المجموع

    لذلك، المزايا الرئيسية وميزات التنفيذ ConcurrentHashMap:

    • hashmapتحتوي الخريطة على واجهة تفاعل مشابهة لـ
    • لا تتطلب عمليات القراءة أقفالًا ويتم تنفيذها بالتوازي
    • غالبًا ما يمكن أيضًا تنفيذ عمليات الكتابة بالتوازي دون حظر
    • عند الإنشاء، تتم الإشارة إلى المطلوب concurrencyLevel، ويتم تحديده من خلال قراءة وكتابة الإحصائيات
    • عناصر الخريطة لها قيمة valueمعلنة كـvolatile
    المصدر: كيف يعمل ConcurrentHashMap

9. ما هي فئة القفل؟

للتحكم في الوصول إلى مورد مشترك، يمكننا استخدام الأقفال كبديل للمشغل المتزامن. يتم حزم وظيفة القفل في java.util.concurrent.locks. أولاً، يحاول مؤشر الترابط الوصول إلى المورد المشترك. إذا كان مجانيا، فسيتم وضع القفل على الخيط. بمجرد اكتمال العمل، يتم تحرير القفل على المورد المشترك. إذا لم يكن المورد مجانيًا وتم وضع قفل عليه بالفعل، فسينتظر الخيط حتى يتم تحرير هذا القفل. تطبق فئات القفل واجهة Lockتحدد الطرق التالية:
  • void lock():ينتظر حتى يتم الحصول على القفل
  • boolean tryLock():يحاول الحصول على القفل؛ إذا تم الحصول على القفل، فإنه يُرجع صحيحًا . إذا لم يتم الحصول على القفل، فإنه يُرجع false . وعلى عكس الطريقة، lock()فإنه لا ينتظر للحصول على القفل إذا لم يكن متاحًا
  • void unlock():يزيل القفل
  • Condition newCondition():إرجاع الكائن Conditionالمرتبط بالقفل الحالي
تنظيم القفل في الحالة العامة بسيط للغاية: للحصول على القفل، يتم استدعاء الطريقة lock()، وبعد الانتهاء من العمل مع الموارد المشتركة، يتم استدعاء الطريقة unlock()، والتي تحرر القفل. يسمح لك الكائن Conditionبإدارة الحظر. كقاعدة عامة، للعمل مع الأقفال، يتم استخدام فئة ReentrantLockمن الحزمة ، java.util.concurrent.locks.وتقوم هذه الفئة بتنفيذ الواجهة Lock. دعونا نلقي نظرة على استخدام Java Lock API باستخدام برنامج صغير كمثال: لذلك، لنفترض أن لدينا فئة Resourceتحتوي على اثنين من الأساليب الآمنة للخيط والأساليب التي لا تتطلب أمان الخيط.
public class Resource {

    public void doSomething(){
        // пусть здесь происходит работа с базой данных
    }

    public void doLogging(){
        // потокобезопасность для логгирования нам не требуется
    }
}
الآن لنأخذ فصلًا دراسيًا ينفذ الواجهة Runnableويستخدم أساليب الفصل Resource.
public class SynchronizedLockExample implements Runnable{

    // экземпляр класса Resource для работы с методами
    private Resource resource;

    public SynchronizedLockExample(Resource r){
        this.resource = r;
    }

    @Override
    public void run() {
        synchronized (resource) {
            resource.doSomething();
        }
        resource.doLogging();
    }
}
الآن دعونا نعيد كتابة البرنامج أعلاه باستخدام Lock API بدلاً من synchronized.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{

    private Resource resource;
    private Lock lock;

    public ConcurrencyLockExample(Resource r){
        this.resource = r;
        this.lock = new ReentrantLock();
    }

    @Override
    public void run() {
        try {
            // лочим на 10 секунд
            if(lock.tryLock(10, TimeUnit.SECONDS)){
            resource.doSomething();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            //убираем лок
            lock.unlock();
        }
        // Для логгирования не требуется потокобезопасность
        resource.doLogging();
    }

}
كما ترون من البرنامج، نحن نستخدم الطريقة tryLock()للتأكد من أن الخيط ينتظر فقط لفترة معينة من الوقت. إذا لم يحصل على قفل على الكائن، فإنه ببساطة يقوم بتسجيل الدخول والخروج. نقطة أخرى مهمة. يجب عليك استخدام كتلة try-finallyللتأكد من أنه سيتم تحرير القفل حتى لو قامت الطريقة doSomething()بطرح استثناء. مصادر:

11. ما هو كائن المزامنة؟

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

12. ما هي الشاشة؟

الشاشة عبارة عن آلية خاصة (قطعة من التعليمات البرمجية) - وظيفة إضافية فوق كائن المزامنة (mutex)، مما يضمن التشغيل الصحيح معها. بعد كل شيء، لا يكفي تحديد أن الكائن مشغول، بل يجب علينا أيضًا التأكد من أن الخيوط الأخرى لا تحاول استخدام الكائن المشغول. في Java، يتم تنفيذ الشاشة باستخدام الكلمة الأساسية synchronized. عندما نكتب كتلة متزامنة، يستبدلها مترجم Java بثلاث أجزاء من التعليمات البرمجية:
  1. في بداية الكتلة synchronized، تتم إضافة التعليمات البرمجية التي تحدد كائن المزامنة على أنه مشغول.
  2. في نهاية الكتلة، synchronizedتتم إضافة رمز يميز كائن المزامنة (mutex) على أنه مجاني.
  3. قبل الكتلة، synchronizedتتم إضافة التعليمات البرمجية التي تتحقق مما إذا كان كائن المزامنة (mutex) مشغولاً، ثم يجب أن ينتظر الخيط حتى يتم تحريره.
الجزء 1
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION