JavaRush /Блоги Java /Random-TG /Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III...
Viacheslav
Сатҳи

Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - Муошират

Дар гурӯҳ нашр шудааст
Шарҳи мухтасари хусусиятҳои мутақобилаи ришта. Пештар, мо дида будем, ки чӣ гуна риштаҳо бо ҳамдигар ҳамоҳанг мешаванд. Ин дафъа мо ба мушкилоте, ки ҳангоми ҳамкории риштаҳо метавонанд ба миён оянд ва дар бораи чӣ гуна пешгирӣ кардани онҳо сӯҳбат кунем. Мо инчунин якчанд истинодҳои муфидро барои омӯзиши амиқтар пешкаш хоҳем кард. Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - ҳамкорӣ - 1

Муқаддима

Ҳамин тавр, мо медонем, ки дар Java риштаҳо мавҷуданд, ки шумо дар бораи онҳо метавонед дар баррасии " Thread Java-ро вайрон карда наметавонад: Қисми I - Threads " ва риштаҳоро бо ҳамдигар ҳамоҳанг кардан мумкин аст, ки мо дар баррасии онҳо баррасӣ кардем " Ришта наметавонад Java-ро вайрон кунад ” Ғамхорӣ: Қисми II - Синхронизатсия ." Вақти он расидааст, ки дар бораи он ки риштаҳо бо ҳамдигар чӣ гуна муносибат мекунанд, сӯҳбат кунем. Чӣ тавр онҳо захираҳои умумиро тақсим мекунанд? Кадом мушкилот бо ин вуҷуд дошта метавонанд?

Сарбаста

Мушкилоти бадтарин ин басташавӣ аст. Вақте ки ду ё зиёда риштаҳо то абад барои ҳамдигар интизор мешаванд, ин басташавӣ номида мешавад. Биёед аз вебсайти Oracle аз тавсифи мафҳуми " Deadlock " мисол гирем:
public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s has bowed to me!%n",
                    this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s has bowed back to me!%n",
                    this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse = new Friend("Alphonse");
        final Friend gaston = new Friend("Gaston");
        new Thread(() -> alphonse.bow(gaston)).start();
        new Thread(() -> gaston.bow(alphonse)).start();
    }
}
Бунбаст дар ин ҷо шояд бори аввал пайдо нашавад, аммо агар иҷрои барномаи шумо часпида бошад, вақти он расидааст, ки иҷро кунед jvisualvm: Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - ҳамкорӣ - 2Агар плагин дар JVisualVM насб карда шавад (тавассути Tools -> Plugins), мо метавонем бубинем, ки бунбаст дар куҷо рух додааст:
"Thread-1" - Thread t@12
   java.lang.Thread.State: BLOCKED
    at Deadlock$Friend.bowBack(Deadlock.java:16)
    - waiting to lock &lt33a78231> (a Deadlock$Friend) owned by "Thread-0" t@11
Риштаи 1 қуфлро аз риштаи 0 интизор аст. Чаро ин рӯй медиҳад? Thread-1иҷроро оғоз мекунад ва методро иҷро мекунад Friend#bow. Он бо калимаи калидӣ қайд карда шудааст synchronized, яъне мо мониторро аз рӯи this. Дар даромадгоҳи усул, мо истиноди дигаре гирифтем Friend. Ҳоло, ришта Thread-1мехоҳад усули дигареро иҷро кунад Friendва ба ин васила аз ӯ низ қулф ба даст орад. Аммо агар риштаи дигар (дар ин ҳолат Thread-0) тавонист ба усул ворид шавад bow, қулф аллакай банд ва Thread-1интизор аст Thread-0ва баръакс. Бастан ҳалнашаванда аст, бинобар ин Мурда аст, яъне мурда аст. Ҳам чанголи марг (ки онро озод кардан мумкин нест) ва ҳам блоки мурдае, ки аз он гурехта наметавонад. Дар мавзӯи бунбаст, шумо метавонед видеоро тамошо кунед: " Сарбаста - Ҳамзамон # 1 - Java Advanced ".

Зиндагӣ

Агар бунбаст вуҷуд дошта бошад, пас Livelock вуҷуд дорад? Бале, вуҷуд дорад) Livelock ин аст, ки риштаҳо аз зоҳир зинда ба назар мерасанд, аммо дар айни замон онҳо коре карда наметавонанд, зеро... шарте, ки онхо барои давом додани кори худ кушиш мекунанд, ичро кардан мумкин нест. Аслан, Livelock ба бунбаст монанд аст, аммо риштаҳо дар система дар интизори монитор "овезон" намешаванд, балки ҳамеша коре мекунанд. Барои намуна:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class App {
    public static final String ANSI_BLUE = "\u001B[34m";
    public static final String ANSI_PURPLE = "\u001B[35m";

    public static void log(String text) {
        String name = Thread.currentThread().getName(); //like Thread-1 or Thread-0
        String color = ANSI_BLUE;
        int val = Integer.valueOf(name.substring(name.lastIndexOf("-") + 1)) + 1;
        if (val != 0) {
            color = ANSI_PURPLE;
        }
        System.out.println(color + name + ": " + text + color);
        try {
            System.out.println(color + name + ": wait for " + val + " sec" + color);
            Thread.currentThread().sleep(val * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Lock first = new ReentrantLock();
        Lock second = new ReentrantLock();

        Runnable locker = () -> {
            boolean firstLocked = false;
            boolean secondLocked = false;
            try {
                while (!firstLocked || !secondLocked) {
                    firstLocked = first.tryLock(100, TimeUnit.MILLISECONDS);
                    log("First Locked: " + firstLocked);
                    secondLocked = second.tryLock(100, TimeUnit.MILLISECONDS);
                    log("Second Locked: " + secondLocked);
                }
                first.unlock();
                second.unlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        new Thread(locker).start();
        new Thread(locker).start();
    }
}
Муваффақияти ин code аз тартибе вобаста аст, ки ҷадвалбандии риштаи Java риштаҳоро оғоз мекунад. Агар он аввал оғоз шавад Thead-1, мо Livelock мегирем:
Thread-1: First Locked: true
Thread-1: wait for 2 sec
Thread-0: First Locked: false
Thread-0: wait for 1 sec
Thread-0: Second Locked: true
Thread-0: wait for 1 sec
Thread-1: Second Locked: false
Thread-1: wait for 2 sec
Thread-0: First Locked: false
Thread-0: wait for 1 sec
...
Тавре ки аз мисол дида мешавад, ҳарду ришта бо навбат кӯшиш мекунанд, ки ҳарду қуфлро гиранд, аммо онҳо ноком мешаванд. Гузашта аз ин, онҳо дар бунбаст нестанд, яъне ба таври визуалӣ ҳама чиз бо онҳо хуб аст ва онҳо кори худро иҷро мекунанд. Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - ҳамкорӣ - 3Мувофиқи JVisualVM, мо давраҳои хоб ва давраи паркро мебинем (ин вақтест, ки ришта қулфро ишғол кардан мехоҳад, он ба ҳолати парк мегузарад, тавре ки мо қаблан ҳангоми сӯҳбат дар бораи ҳамоҳангсозии ришта муҳокима кардем ). Дар мавзӯи livelock, шумо метавонед як мисолро бинед: " Java - Thread Livelock ".

Гуруснагӣ

Илова ба басташавӣ (қуфл ва басташавӣ), мушкилоти дигар ҳангоми кор бо мултипликатор вуҷуд дорад - Гуруснагӣ ё "гуруснагӣ". Ин падида аз басташавӣ бо он фарқ мекунад, ки риштаҳо баста нашудаанд, аммо онҳо барои ҳама захираҳои кофӣ надоранд. Аз ин рӯ, дар ҳоле ки баъзе риштаҳо тамоми вақти иҷроро мегиранд, дигарон наметавонанд иҷро шаванд: Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - ҳамкорӣ - 4

https://www.logicbig.com/

Намунаи олиро дар ин ҷо пайдо кардан мумкин аст: " Java - Гуруснагӣ ва адолат ". Ин мисол нишон медиҳад, ки чӣ тавр риштаҳо дар гуруснагӣ кор мекунанд ва чӣ гуна як тағири хурд аз Thread.sleep ба Thread.wait метавонад сарборро баробар тақсим кунад. Шумо наметавонед Java-ро бо ришта вайрон кунед: Қисми III - ҳамкорӣ - 5

Ҳолати мусобиқа

Ҳангоми кор бо multithreading, чунин чизе ба монанди "шарти мусобиқа" вуҷуд дорад. Ин падида дар он аст, ки риштаҳо як манбаи муайянро байни худ тақсим мекунанд ва code тавре навишта шудааст, ки дар ин ҳолат кори дурустро таъмин намекунад. Биёед як мисолро дида бароем:
public class App {
    public static int value = 0;

    public static void main(String[] args) {
        Runnable task = () -> {
            for (int i = 0; i < 10000; i++) {
                int oldValue = value;
                int newValue = ++value;
                if (oldValue + 1 != newValue) {
                    throw new IllegalStateException(oldValue + " + 1 = " + newValue);
                }
            }
        };
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
    }
}
Ин code метавонад бори аввал хато эҷод накунад. Ва он метавонад чунин бошад:
Exception in thread "Thread-1" java.lang.IllegalStateException: 7899 + 1 = 7901
    at App.lambda$main$0(App.java:13)
    at java.lang.Thread.run(Thread.java:745)
Тавре ки шумо мебинед, ҳангоми таъин кардани он, newValueчизе нодуруст рафт ва newValueбоз ҳам зиёдтар буданд. Баъзе риштаҳо дар ҳолати мусобиқа тавонистанд valueбайни ин ду даста иваз шаванд. Чунон ки мебинем, мусобикаи байни риштахо пайдо шудааст. Акнун тасаввур кунед, ки то чӣ андоза муҳим аст, ки ба хатогиҳои шабеҳ дар муомилоти пулӣ роҳ надиҳед... Мисолҳо ва диаграммаҳоро дар инҷо низ пайдо кардан мумкин аст: “ Code to simulate state race in Java thread ”.

Ноустувор

Дар бораи таъсири мутақобилаи риштаҳо сухан ронда, махсусан калимаи калидиро қайд кардан лозим аст volatile. Биёед як мисоли оддиро бубинем:
public class App {
    public static boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        Runnable whileFlagFalse = () -> {
            while(!flag) {
            }
            System.out.println("Flag is now TRUE");
        };

        new Thread(whileFlagFalse).start();
        Thread.sleep(1000);
        flag = true;
    }
}
Аз ҳама ҷолиб он аст, ки бо эҳтимолияти баланди он кор намекунад. Риштаи нав тағиротро намебинад flag. Барои ислоҳ кардани ин, flagшумо бояд калимаи калидиро барои майдон муайян кунед volatile. Чӣ тавр ва чаро? Ҳама амалҳо аз ҷониби протсессор иҷро карда мешаванд. Аммо натиљањои њисобкуниро дар ягон љо нигоњ доштан лозим аст. Бо ин мақсад дар протсессори хотираи асосӣ ва кэши сахтафзор мавҷуд аст. Ин кэшҳои протсессор мисли як пораи хурди хотира барои дастрасии маълумот нисбат ба хотираи асосӣ зудтар мебошанд. Аммо ҳама чиз як нуқсон дорад: маълумот дар кэш метавонад ҷорӣ набошад (чунон ки дар мисоли боло, вақте ки арзиши парчам нав карда нашудааст). Ҳамин тавр, калимаи калидӣ volatileба JVM мегӯяд, ки мо тағирёбандаи худро кэш кардан намехоҳем. Ин ба шумо имкон медиҳад, ки натиҷаи воқеиро дар ҳама риштаҳо бубинед. Ин як формулаи хеле соддакардашуда аст. Дар ин мавзӯъ, volatileтавсия дода мешавад, ки тарҷумаи " JSR 133 (Java Memory Model) FAQ -ро хонед . Ман инчунин ба шумо маслиҳат медиҳам, ки дар бораи маводҳои " Java Memory Model " ва " Java Keyword Keyword " бештар хонед. Илова бар ин, дар хотир доштан муҳим аст, ки volatileин дар бораи аёният аст, на дар бораи атомии тағирот. Агар мо рамзро аз "Ҳолати нажод" гирем, мо дар IntelliJ Idea ишора хоҳем кард: Thread'ом Java не испортишь: Часть III — взаимодействие - 6Ин санҷиш (Инспекция) ба IntelliJ Idea ҳамчун як қисми нашри IDEA-61117 , ки дар ёддоштҳои нашр дар соли 2010 номбар шуда буд, илова карда шудааст.

Атомизм

Амалиёти атомӣ амалиётҳое мебошанд, ки онҳоро тақсим кардан мумкин нест. Масалан, амалиёти таъини арзиш ба тағирёбанда атомист. Мутаассифона, афзоиш амалиёти атомӣ нест, зеро як афзоиш то се амалиётро талаб мекунад: арзиши кӯҳнаро гиред, ба он як илова кунед ва арзишро захира кунед. Чаро атом муҳим аст? Дар мисоли афзоиш, агар ҳолати мусобиқа рух диҳад, дар ҳама вақт манбаи муштарак (яъне арзиши муштарак) метавонад ногаҳон тағир ёбад. Илова бар ин, муҳим аст, ки сохторҳои 64-бит низ атомӣ нестанд, масалан longва double. Шумо метавонед маълумоти бештарро дар ин ҷо хонед: " Ҳангоми хондан ва навиштани арзишҳои 64-бит атомиро таъмин кунед ". Намунаи мушкилоти атомиро дар мисоли зерин дидан мумкин аст:
public class App {
    public static int value = 0;
    public static AtomicInteger atomic = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            for (int i = 0; i < 10000; i++) {
                value++;
                atomic.incrementAndGet();
            }
        };
        for (int i = 0; i < 3; i++) {
            new Thread(task).start();
        }
        Thread.sleep(300);
        System.out.println(value);
        System.out.println(atomic.get());
    }
}
Синфи махсус барои кор бо атом Integerҳамеша ба мо 30000 нишон медиҳад, аммо valueон вақт ба вақт тағйир меёбад. Шарҳи мухтасари ин мавзӯъ " Муқаддима ба тағирёбандаҳои атомӣ дар Java " мавҷуд аст. Atomic ба алгоритми муқоиса ва ивазкунӣ асос ёфтааст. Шумо метавонед бештар дар ин бора дар мақолаи Habré " Муқоисаи алгоритмҳои беқулф - CAS ва FAA бо истифода аз мисоли JDK 7 ва 8 " ё дар Википедиа дар мақолаи " Муқоиса бо мубодила " хонед. Thread'ом Java не испортишь: Часть III — взаимодействие - 8

http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html

Пеш аз он рӯй медиҳад

Як чизи ҷолиб ва пурасрор вуҷуд дорад - Пештар рӯй медиҳад. Дар бораи ҷараёнҳо сухан ронда, дар бораи он низ хондан меарзад. Муносибати пеш аз рӯйдодҳо тартиби дидани амалҳои байни риштаҳоро нишон медиҳад. Бисёр тафсирҳо ва тафсирҳо мавҷуданд. Яке аз гузоришҳои охирин дар ин мавзӯъ ин гузориш аст:
Эҳтимол беҳтар аст, ки ин видео дар бораи он чизе нагӯяд. Пас, ман танҳо як истинод ба видео мегузорам. Шумо метавонед " Java - Фаҳмидани муносибатҳо пеш аз муносибатҳо " -ро хонед.

Натиҷаҳо

Дар ин барраси, мо ба хусусиятҳои мутақобилаи ришта назар кардем. Мо дар бораи мушкилоте, ки метавонанд ба миён оянд ва роҳҳои ошкор ва бартараф кардани онҳоро баррасӣ кардем. Рӯйхати маводи иловагӣ оид ба мавзӯъ: #Вячеслав
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION