Sobes.tech
Middle

Ի՞նչ է Java-ի synchronized բլոկը և ինչ խնդիրներ կարող են առաջանալ դրա օգտագործման ժամանակ։

sobes.tech AI

Պատասխան AI-ից

Java-յի synchronized բլոկը օգտագործվում է ընդհանուր ռեսուրսին մուտքի սինխրոնիզացիան ապահովելու համար մի քանի թելերի միջև։ Դա երաշխավորում է, որ միայն մեկ թել կարող է կատարել բլոկի ներսում գտնվող կոդը ցանկացած ժամանակ:

synchronized բլոկի կառուցվածքը՝

synchronized (մոնիտոր_օբյեկտ) {
    // Կրիտիկական հատված
    // Այստեղ կատարվում են ընդհանուր ռեսուրսի հետ գործողություններ
}
  • մոնիտոր_օբյեկտ: ցանկացած օբյեկտ, որը ծառայում է որպես մոնիտոր (լոկ). Թելերը, որոնք փորձում են մուտք գործել synchronized բլոկը նույն օբյեկտով, կլանվեն մինչև որ ընթացիկ թելը դուրս գա բլոկից:

Հնարավոր խնդիրներ՝

  • Deadlock (մահացու լոկացում): Երկու կամ ավելի թելեր սպասում են ռեսուրսի ազատմանը, որը զբաղեցված է այլ թելով, ինչը հանգեցնում է ծրագրի կանգառի։ Դա կարող է տեղի ունենալ, եթե թելերը փորձում են ստանալ լոկեր տարբեր կարգով:

  • Ավելի ցածր արդյունավետություն: Սինխրոնիզացիան խոչընդոտում է մյուս թելերի կատարմանը, որոնք սպասում են մոնիտորի հասանելիությանը, ինչը կարող է դանդաղեցնել ծրագրի աշխատանքը:

  • Որոշ սցենարներում կիրառելի չէ: synchronized-ը ապահովում է բացառիկ մուտք։ Որոշ դեպքերում կարող է անհրաժեշտ լինել ավելի ճկուն մուտքի կառավարում (օր., միաժամանակ մի քանի թելերից ընթերցում, գրառում մեկ թելից):

  • Համակարգման բարդություն: Սինխրոնիզացիայի խնդիրները կարող են լինել աննկատ և դժվար վերարտադրել և դետեկցել:

Նմուշ՝

class Resource {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1(Resource other) {
        synchronized (lock1) {
            try {
                Thread.sleep(100); // Աշխատանքի իմիտացիա
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " ձեռք բերեց lock1");
            synchronized (other.lock2) {
                System.out.println(Thread.currentThread().getName() + " ձեռք բերեց lock2-ի մյուսը");
            }
        }
    }

    public void method2(Resource other) {
        synchronized (lock2) {
             try {
                Thread.sleep(100); // Աշխատանքի իմիտացիա
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " ձեռք բերեց lock2");
            synchronized (other.lock1) {
                System.out.println(Thread.currentThread().getName() + " ձեռք բերեց lock1-ի մյուսը");
            }
        }
    }
}

public class DeadlockExample {
    public static void main(String[] args) {
        Resource r1 = new Resource();
        Resource r2 = new Resource();

        new Thread(() -> r1.method1(r2), "Thread-1").start();
        new Thread(() -> r2.method2(r1), "Thread-2").start();
    }
}

Այս օրինակով, Thread-1 փորձում է ձեռք բերել lock1-ը r1-ում և հետո lock2-ը r2-ում։ Thread-2 փորձում է ձեռք բերել lock2-ը r2-ում և հետո lock1-ը r1-ում։ Եթե նրանք ձեռք բերեն առաջին լոկերը միաժամանակ, կստեղծվի փոխադարձ լոկացում։