JavaRush /Blog Jawa /Random-JV /Sampeyan Ora Bisa Ngrusak Jawa Kanthi Utas: Part III - In...
Viacheslav
tingkat

Sampeyan Ora Bisa Ngrusak Jawa Kanthi Utas: Part III - Interaksi

Diterbitake ing grup
Ringkesan ringkes babagan fitur interaksi benang. Sadurunge, kita ndeleng carane benang disinkronake. Wektu iki kita bakal nyilem menyang masalah sing bisa muncul nalika thread sesambungan lan ngomong babagan carane bisa nyingkiri. Kita uga bakal nyedhiyani sawetara pranala migunani kanggo sinau luwih jero. Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 1

Pambuka

Dadi, kita ngerti manawa ana benang ing Jawa, sing bisa diwaca ing review " Utas Ora Bisa Ngrusak Jawa: Bagian I - Utas "lan Utas bisa disinkronake karo saben liyane, sing ditangani ing review " Utas Ora Bisa Ngrusak Jawa ” Spoil: Part II - Sinkronisasi ." Iku wektu kanggo pirembagan bab carane Utas sesambungan karo saben liyane. Kepiye cara nuduhake sumber daya umum? Apa masalah bisa ana karo iki?

Deadlock

Masalah paling awon yaiku Deadlock. Nalika loro utawa luwih Utas ngenteni ing salawas-lawase kanggo saben liyane, iki disebut Deadlock. Ayo njupuk conto saka situs web Oracle saka deskripsi konsep " 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();
    }
}
Deadlock ing kene bisa uga ora katon sepisanan, nanging yen eksekusi program sampeyan macet, wektune kanggo mbukak jvisualvm: Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 2Yen plugin diinstal ing JVisualVM (liwat Tools -> Plugins), kita bisa ndeleng ing endi deadlock:
"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
Utas 1 ngenteni kunci saka utas 0. Yagene iki kedadeyan? Thread-1miwiti eksekusi lan nglakokake metode kasebut Friend#bow. Iki ditandhani karo tembung kunci synchronized, yaiku, kita njupuk monitor kanthi this. Ing ngleboke cara, kita nampa link menyang liyane Friend. Saiki, utas kasebut Thread-1pengin nglakokake metode liyane Friend, saengga entuk kunci saka dheweke uga. Nanging yen thread liyane (ing kasus iki Thread-0) bisa ngetik cara bow, banjur kunci wis sibuk lan Thread-1nunggu Thread-0, lan kosok balene. Pamblokiran ora bisa ditanggulangi, dadi Mati, yaiku mati. Loro-lorone genggeman pati (sing ora bisa dibebasake) lan blok mati sing ora bisa uwal. Ing topik deadlock, sampeyan bisa nonton video: " Deadlock - Concurrency #1 - Advanced Java ".

Livelock

Yen ana Deadlock, banjur ana Livelock? Ya, ana) Livelock yaiku yen benang katon urip ing njaba, nanging ing wektu sing padha ora bisa nindakake apa-apa, amarga ... kahanan kang lagi nyoba kanggo nerusake karya ora bisa ketemu. Intine, Livelock padha karo deadlock, nanging benang ora "nyumerepi" ing sistem nunggu monitor, nanging tansah nindakake apa-apa. Tuladhane:
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();
    }
}
Kasuksesan kode iki gumantung saka urutane penjadwal thread Jawa miwiti thread. Yen diwiwiti dhisik Thead-1, kita bakal entuk 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
...
Minangka bisa dideleng saka conto, loro Utas gantian nyoba kanggo nangkep loro kunci, nanging padha gagal. Kajaba iku, dheweke ora ana ing deadlock, yaiku, kanthi visual kabeh apik karo dheweke lan nindakake tugase. Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 3Miturut JVisualVM, kita ndeleng suwé turu lan periode taman (iki nalika thread nyoba kanggo Occupy kunci, iku dadi menyang negara taman, kita rembugan sadurungé nalika ngomong bab sinkronisasi thread ). Ing topik livelock, sampeyan bisa ndeleng conto: " Java - Thread Livelock ".

keluwen

Saliyane pamblokiran (deadlock lan livelock), ana masalah liyane nalika nggarap multithreading - Keluwen, utawa "keluwen". Fenomena iki beda karo pamblokiran amarga benang ora diblokir, nanging mung ora duwe sumber daya sing cukup kanggo kabeh wong. Mulane, nalika sawetara utas njupuk kabeh wektu eksekusi, liyane ora bisa dieksekusi: Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 4

https://www.logicbig.com/

Conto super bisa ditemokake ing kene: " Java - Thread Starvation and Fairness ". Conto iki nuduhake carane Utas bisa digunakake ing Kelaparan lan carane siji owah-owahan cilik saka Thread.sleep kanggo Thread.wait bisa disebaraké mbukak roto-roto. Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 5

Kondisi Balapan

Nalika nggarap multithreading, ana "kondisi balapan". Fenomena iki dumunung ing kasunyatan manawa benang nuduhake sumber daya tartamtu lan kode kasebut ditulis kanthi cara sing ora nyedhiyakake operasi sing bener ing kasus iki. Ayo katon ing conto:
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();
    }
}
Kode iki bisa uga ora ngasilake kesalahan nalika sepisanan. Lan bisa uga katon kaya iki:
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)
Kaya sing sampeyan ngerteni, nalika ditugasake, newValueana sing salah lan newValueana liyane. Sawetara benang ing kondisi balapan bisa diganti valueing antarane rong tim kasebut. Kaya sing kita deleng, balapan antarane benang wis muncul. Saiki mbayangno sepira pentinge ora nggawe kesalahan sing padha karo transaksi dhuwit ... Conto lan diagram uga bisa dideleng ing kene: " Kode kanggo simulasi kondisi balapan ing benang Jawa ".

molah malih

Ngomong babagan interaksi benang, utamane kudu dicathet tembung kunci volatile. Ayo katon ing conto prasaja:
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;
    }
}
Ingkang paling menarik yaiku kanthi kemungkinan sing dhuwur ora bakal bisa digunakake. Utas anyar ora bakal weruh owah-owahan flag. Kanggo ndandani iki, flagsampeyan kudu nemtokake tembung kunci kanggo lapangan volatile. Kepiye lan kenapa? Kabeh tumindak ditindakake dening prosesor. Nanging asil pitungan kudu disimpen ing ngendi wae. Kanggo maksud iki, ana memori utama lan cache hardware ing prosesor. Cache prosesor iki kaya sepotong memori cilik kanggo ngakses data luwih cepet tinimbang ngakses memori utama. Nanging kabeh uga duwe kekurangan: data ing cache bisa uga ora saiki (kaya ing conto ing ndhuwur, nalika nilai gendera ora dianyari). Dadi, tembung kunci kasebut volatilengandhani JVM yen kita ora pengin cache variabel kita. Iki ngidini sampeyan ndeleng asil nyata ing kabeh thread. Iki minangka formulasi sing gampang banget. Ing topik iki, volatiledianjurake banget kanggo maca terjemahan " JSR 133 (Java Memory Model) FAQ ". Aku uga menehi saran supaya maca luwih akeh babagan materi " Model Memori Jawa "lan" Kata Kunci Java Volatile ". Kajaba iku, iku penting kanggo elinga yen volatileiki babagan visibilitas, lan ora babagan atomicity saka owah-owahan. Yen kita njupuk kode saka "Kahanan Balapan", kita bakal weruh pitunjuk ing IntelliJ Idea: Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 6Pemriksaan iki (Inspeksi) ditambahake menyang IntelliJ Idea minangka bagean saka masalah IDEA-61117 , sing kadhaptar ing Cathetan Rilis ing taun 2010.

Atomity

Operasi atom yaiku operasi sing ora bisa dipérang. Contone, operasi menehi nilai kanggo variabel yaiku atom. Sayange, increment dudu operasi atom, amarga Tambah mbutuhake telung operasi: entuk nilai lawas, nambah siji, lan nyimpen nilai kasebut. Apa sebabe atomisitas penting? Ing conto increment, yen ana kahanan lomba, ing sembarang wektu sumber daya sing dienggo bareng (yaiku, nilai bareng) bisa dumadakan ngganti. Kajaba iku, iku penting sing struktur 64-dicokot uga ora atom, contone longlan double. Sampeyan bisa maca liyane ing kene: " Priksa atomicity nalika maca lan nulis nilai 64-bit ". Conto masalah karo atomicity bisa dideleng ing conto ing ngisor iki:
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());
    }
}
Kelas khusus kanggo nggarap atom Integerbakal tansah nuduhake kita 30000, nanging valuebakal diganti saka wektu kanggo wektu. Ana ringkesan ringkes babagan topik iki " Pengantar Variabel Atom ing Jawa ". Atom adhedhasar algoritma Compare-and-Swap. Sampeyan bisa maca liyane babagan iki ing artikel ing Habré " Comparison of Lock-free algoritma - CAS lan FAA nggunakake conto JDK 7 lan 8 " utawa ing Wikipedia ing artikel babagan " Comparison with exchange ". Sampeyan ora bisa ngrusak Jawa nganggo utas: Part III - interaksi - 8

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

Mengkono Sadurunge

Ana sing menarik lan misterius - Mengkono Sadurunge. Ngomong babagan aliran, sampeyan uga kudu maca babagan iki. Hubungan sing kedadeyan sadurunge nuduhake urutan tumindak ing antarane benang bakal katon. Ana akeh interpretasi lan interpretasi. Salah sawijining laporan paling anyar babagan topik iki yaiku laporan iki:
Sampeyan mbokmenawa luwih apik yen video iki ora ngandhani apa-apa. Dadi aku mung bakal ninggalake link menyang video. Sampeyan bisa maca " Java - Understanding Happens-before relationships ".

Asil

Ing review iki, kita ndeleng fitur interaksi benang. Kita ngrembug masalah sing bisa kedadeyan lan cara kanggo ndeteksi lan ngilangi. Dhaptar materi tambahan babagan topik: #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION