KodeGym/Blog Jawa/Acak/Luwih apik bebarengan: Jawa lan kelas Utas. Bagean III - ...
John Squirrels
tingkat
San Francisco

Luwih apik bebarengan: Jawa lan kelas Utas. Bagean III - Interaksi

Diterbitake ing grup
Ringkesan ringkes babagan rincian babagan cara sesambungan benang. Sadurunge, kita ndeleng carane benang disinkronake karo siji liyane. Wektu iki, kita bakal nyilem menyang masalah sing bisa kedadeyan nalika benang sesambungan, lan kita bakal ngrembug babagan cara nyingkiri. Kita uga bakal nyedhiyani sawetara pranala migunani kanggo sinau luwih jero. Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 1

Pambuka

Dadi, kita ngerti yen Jawa duwe benang. Sampeyan bisa maca babagan kasebut ing review kanthi irah-irahan Better together: Java and the Thread class. Bagian I - Utas eksekusi . Lan kita njelajah kasunyatan manawa benang bisa nyinkronake siji liyane ing review kanthi judhul Better together: Java and the Thread class. Bagean II - Sinkronisasi . Iku wektu kanggo pirembagan bab carane Utas sesambungan karo siji liyane. Kepiye cara nuduhake sumber daya sing dienggo bareng? Masalah apa sing bisa kedadeyan ing kene? Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 2

Deadlock

Masalah sing paling medeni kabeh yaiku deadlock. Deadlock yaiku nalika loro utawa luwih utas tansah nunggu liyane. Kita bakal njupuk conto saka kaca web Oracle sing nggambarake 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 bowed to me!%n",
                    this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s 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 bisa uga ora kedadeyan ing kene sepisanan, nanging yen program sampeyan macet, mula wektune kanggo mbukak jvisualvm: Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 3Kanthi plugin JVisualVM diinstal (liwat Tools -> Plugins), kita bisa ndeleng ing ngendi deadlock kasebut kedadeyan:
"Thread-1" - Thread t@12
   java.lang.Thread.State: BLOCKED
	at Deadlock$Friend.bowBack(Deadlock.java:16)
	- waiting to lock <33a78231> (a Deadlock$Friend) owned by "Thread-0" t@11
Utas 1 ngenteni kunci saka utas 0. Apa sebabe? Thread-1wiwit mlaku lan nglakokaké Friend#bowcara. Iki ditandhani karo synchronizedtembung kunci, tegese kita entuk monitor kanggo this(obyek saiki). Input metode kasebut minangka referensi kanggo Friendobyek liyane. Saiki, Thread-1pengin nglakokake metode kasebut ing sisih liyane Friend, lan kudu entuk kunci kanggo nindakake. Nanging yen thread liyane (ing kasus iki Thread-0) bisa ngetik bow()cara, banjur kunci wis angsal lan Thread-1ngenteniThread-0, lan kosok balene. Iki impasse ora bisa diatasi, lan kita nyebataken deadlock. Ibarat genggeman maut sing ora bisa diuculake, deadlock iku saling pamblokiran sing ora bisa dipecah. Kanggo panjelasan liyane babagan deadlock, sampeyan bisa nonton video iki: Deadlock lan Livelock Explained .

Livelock

Yen ana deadlock, ana uga livelock? Ya, ana :) Livelock kedadeyan nalika benang katon urip, nanging ora bisa nindakake apa-apa, amarga syarat-syarat sing dibutuhake kanggo nerusake karyane ora bisa ditindakake. Sejatine, livelock padha karo deadlock, nanging benang ora "nyumerepi" nunggu monitor. Nanging, padha tansah nindakake soko. 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 Thead-1diwiwiti dhisik, banjur 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 sampeyan bisa ndeleng saka conto, loro Utas nyoba kanggo ndarbeni loro kunci ing siji, nanging padha gagal. Nanging, dheweke ora ana ing deadlock. Ing njaba, kabeh apik lan padha nindakake pakaryane. Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 4Miturut JVisualVM, kita ndeleng wektu turu lan periode taman (iki nalika thread nyoba kanggo ndarbeni kunci - iku lumebu ing negara taman, kita rembugan sadurungé nalika kita ngomong bab sinkronisasi thread ) . Sampeyan bisa ndeleng conto livelock ing kene: Java - Thread Livelock .

keluwen

Saliyane deadlock lan livelock, ana masalah liyane sing bisa kedadeyan sajrone multithreading: keluwen. Fenomena iki beda karo wangun pamblokiran sadurunge amarga benang ora diblokir - mung ora duwe sumber daya sing cukup. Akibaté, nalika sawetara utas njupuk kabeh wektu eksekusi, liyane ora bisa mbukak: Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 5

https://www.logicbig.com/

Sampeyan bisa ndeleng conto super ing kene: Jawa - Kelaparan Utas lan Keadilan . Conto iki nuduhake apa sing kedadeyan karo benang sajrone keluwen lan kepiye owah-owahan cilik saka Thread.sleep()supaya Thread.wait()sampeyan bisa nyebarake beban kanthi merata. Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 6

Kondisi balapan

Ing multithreading, ana sing kaya "kondisi balapan". Fenomena iki kedadeyan nalika benang nuduhake sumber daya, nanging kode kasebut ditulis kanthi cara sing ora njamin enggo bareng sing bener. Delengen contone:
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. Nalika iku, bisa 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, ana sing salah nalika newValuediwenehi nilai. newValuegedhe banget. Amarga kahanan balapan, salah sawijining benang bisa ngganti variabel valueing antarane rong pernyataan kasebut. Pranyata ana lomba antarane Utas. Saiki mikir babagan pentinge ora nggawe kesalahan sing padha karo transaksi moneter ... Conto lan diagram uga bisa dideleng ing kene: Kode kanggo simulasi kondisi balapan ing benang Jawa .

molah malih

Ngomong babagan interaksi benang, volatiletembung kunci kasebut kudu disebutake. 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;
    }
}
Sing paling menarik, iki kemungkinan ora bisa digunakake. Utas anyar ora bakal weruh owah-owahan ing flaglapangan. Kanggo ndandani iki kanggo flaglapangan, kita kudu nggunakake volatiletembung kunci. Kepiye lan kenapa? Prosesor nindakake kabeh tumindak. Nanging asil petungan kudu disimpen ing ngendi wae. Kanggo iki, ana memori utama lan ana cache prosesor. Cache prosesor kaya potongan cilik saka memori sing digunakake kanggo ngakses data luwih cepet tinimbang nalika ngakses memori utama. Nanging kabeh duwe kekurangan: data ing cache bisa uga ora anyar (kaya ing conto ing ndhuwur, nalika nilai kolom gendera ora dianyari). Dadi, ingvolatiletembung kunci ngandhani JVM yen kita ora pengin cache variabel kita. Iki ngidini asil paling anyar katon ing kabeh utas. Iki panjelasan Highly simplified. Kanggo volatiletembung kunci, aku banget nyaranake sampeyan maca artikel iki . Kanggo informasi luwih lengkap, aku uga menehi saran supaya maca Model Memori Jawa lan Kata Kunci Volatile Jawa . Kajaba iku, penting kanggo elinga volatilebabagan visibilitas, lan dudu babagan atomisitas owah-owahan. Deleng kode ing bagean "Kahanan balapan", kita bakal weruh tooltip ing IntelliJ IDEA: Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 7Pemriksaan iki 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 kudu atom. Sayange, operasi increment dudu atom, amarga increment mbutuhake nganti telung operasi CPU: entuk nilai lawas, tambahake siji, banjur simpen nilai kasebut. Apa sebabe atomisitas penting? Kanthi operasi increment, yen ana kondisi lomba, banjur sumber daya sing dienggo bareng (yaiku nilai sing dienggo bareng) bisa dumadakan ganti kapan wae. Kajaba iku, operasi sing nglibatake struktur 64-bit, contone longlan double, ora atom. Rincian liyane bisa diwaca ing kene: Njamin atomicity nalika maca lan nulis nilai 64-bit . Masalah sing ana gandhengane karo atomisitas bisa dideleng ing conto 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 AtomicIntegerbakal tansah menehi kita 30.000, nanging valuebakal diganti saka wektu kanggo wektu. Ana ringkesan ringkes babagan topik iki: Pengantar Variabel Atom ing Jawa . Algoritma "bandhingake-lan-swap" dumunung ing jantung kelas atom. Sampeyan bisa maca liyane babagan kene ing Comparison of lock-free algorithm - CAS lan FAA ing conto JDK 7 lan 8 utawa ing artikel Compare-and-swap ing Wikipedia. Luwih apik bebarengan: Jawa lan kelas Utas.  Bagean III - Interaksi - 9

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

Mengkono-sadurunge

Ana konsep sing menarik lan misterius sing diarani "kedadeyan sadurunge". Minangka bagéan saka sinau thread, sampeyan kudu maca babagan. Hubungan sing kedadeyan sadurunge nuduhake urutan tumindak ing antarane benang bakal katon. Ana akeh interpretasi lan komentar. Iki minangka salah sawijining presentasi paling anyar babagan topik iki: Hubungan "Kedadeyan-Sadurunge" Jawa .

Ringkesan

Ing review iki, kita wis njelajah sawetara spesifik babagan carane benang sesambungan. Kita ngrembug masalah sing bisa kedadeyan, uga cara kanggo ngenali lan ngilangi. Dhaptar materi tambahan babagan topik: Luwih apik bebarengan: Jawa lan kelas Utas. Bagian I - Utas eksekusi Luwih apik bebarengan: Jawa lan kelas Utas. Part II - Sinkronisasi Luwih apik bebarengan: Jawa lan kelas Utas. Part IV - Callable, Future, lan kanca-kanca Luwih apik bebarengan: Jawa lan kelas Utas. Part V - Executor, ThreadPool, Fork / Gabung luwih apik bebarengan: Jawa lan kelas Utas. Bab VI - Mbusak!
Komentar
  • Popular
  • Anyar
  • lawas
Sampeyan kudu mlebu kanggo ninggalake komentar
Kaca iki durung duwe komentar