JavaRush /Blog Java /Random-MS /Anda tidak boleh merosakkan Java dengan benang: Bahagian ...

Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan

Diterbitkan dalam kumpulan

pengenalan

Jadi, kami tahu bahawa terdapat benang dalam Java, yang boleh anda baca dalam ulasan " Anda Tidak Boleh Merosakkan Java dengan Benang: Bahagian I - Benang ". Benang diperlukan untuk melakukan kerja secara serentak. Oleh itu, kemungkinan besar benang akan berinteraksi antara satu sama lain. Mari kita fahami bagaimana ini berlaku dan apakah kawalan asas yang kita ada. Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 1

hasil

Kaedah Thread.yield() adalah misteri dan jarang digunakan. Terdapat banyak variasi penerangannya di Internet. Sehinggakan ada yang menulis tentang beberapa jenis barisan benang, di mana benang itu akan bergerak ke bawah dengan mengambil kira keutamaan mereka. Seseorang menulis bahawa utas akan menukar statusnya daripada berjalan kepada runnable (walaupun tiada pembahagian ke dalam status ini, dan Java tidak membezakan antara mereka). Tetapi pada hakikatnya, semuanya lebih tidak diketahui dan, dalam erti kata lain, lebih mudah. Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 2Mengenai topik dokumentasi kaedah, yieldterdapat pepijat " JDK-6416721: (benang spesifikasi) Betulkan Thread.yield() javadoc ". Jika anda membacanya, adalah jelas bahawa sebenarnya kaedah itu yieldhanya menyampaikan beberapa cadangan kepada penjadual benang Java bahawa benang ini boleh diberi masa pelaksanaan yang lebih sedikit. Tetapi apa yang sebenarnya akan berlaku, sama ada penjadual akan mendengar cadangan dan apa yang akan dilakukan secara umum bergantung pada pelaksanaan JVM dan sistem pengendalian. Atau mungkin dari beberapa faktor lain. Semua kekeliruan itu berkemungkinan besar disebabkan oleh pemikiran semula multithreading semasa pembangunan bahasa Jawa. Anda boleh membaca lebih lanjut dalam ulasan " Pengenalan Ringkas kepada Java Thread.yield() ".

Tidur - Benang tertidur

Seutas benang mungkin tertidur semasa pelaksanaannya. Ini adalah jenis interaksi yang paling mudah dengan utas lain. Sistem pengendalian di mana mesin maya Java dipasang, di mana kod Java dilaksanakan, mempunyai penjadual benang sendiri, dipanggil Penjadual Benang. Dialah yang memutuskan benang mana yang hendak dijalankan. Pengaturcara tidak boleh berinteraksi dengan penjadual ini terus daripada kod Java, tetapi dia boleh, melalui JVM, meminta penjadual untuk menjeda utas untuk seketika, untuk "meletakkannya." Anda boleh membaca lebih lanjut dalam artikel " Thread.sleep() " dan " How Multithreading works ". Selain itu, anda boleh mengetahui cara benang berfungsi dalam Windows OS: " Dalaman Windows Thread ". Sekarang kita akan melihatnya dengan mata kita sendiri. Mari simpan kod berikut pada fail HelloWorldApp.java:
class HelloWorldApp {
    public static void main(String []args) {
        Runnable task = () -> {
            try {
                int secToWait = 1000 * 60;
                Thread.currentThread().sleep(secToWait);
                System.out.println("Waked up");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Seperti yang anda lihat, kami mempunyai tugasan yang menunggu 60 saat, selepas itu program tamat. Kami menyusun javac HelloWorldApp.javadan menjalankan java HelloWorldApp. Adalah lebih baik untuk melancarkan dalam tetingkap berasingan. Sebagai contoh, pada Windows ia akan menjadi seperti ini: start java HelloWorldApp. Menggunakan arahan jps, kami mengetahui PID proses dan membuka senarai utas menggunakan jvisualvm --openpid pidПроцесса: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 3Seperti yang anda lihat, utas kami telah memasuki status Tidur. Malah, tidur benang semasa boleh dilakukan dengan lebih indah:
try {
	TimeUnit.SECONDS.sleep(60);
	System.out.println("Waked up");
} catch (InterruptedException e) {
	e.printStackTrace();
}
Anda mungkin perasan bahawa kami memproses di mana-mana sahaja InterruptedException? Mari kita fahami mengapa.

Mengganggu benang atau Benang.gangguan

Masalahnya ialah semasa benang menunggu dalam tidur, seseorang mungkin mahu mengganggu penantian ini. Dalam kes ini, kami mengendalikan pengecualian sedemikian. Ini dilakukan selepas kaedah itu Thread.stopdiisytiharkan Dihentikan, i.e. ketinggalan zaman dan tidak diingini untuk digunakan. Sebabnya ialah apabila kaedah itu dipanggil, stopbenang itu hanya "dibunuh", yang sangat tidak dapat diramalkan. Kami tidak dapat mengetahui bila aliran akan dihentikan, kami tidak dapat menjamin ketekalan data. Bayangkan anda sedang menulis data ke fail dan kemudian aliran itu dimusnahkan. Oleh itu, mereka memutuskan bahawa adalah lebih logik untuk tidak membunuh aliran, tetapi memaklumkannya bahawa ia harus diganggu. Bagaimana untuk bertindak balas terhadap perkara ini terpulang kepada aliran itu sendiri. Butiran lanjut boleh didapati dalam Oracle " Mengapa Thread.stop ditamatkan? " Mari lihat contoh:
public static void main(String []args) {
	Runnable task = () -> {
		try {
			TimeUnit.SECONDS.sleep(60);
		} catch (InterruptedException e) {
			System.out.println("Interrupted");
		}
	};
	Thread thread = new Thread(task);
	thread.start();
	thread.interrupt();
}
Dalam contoh ini, kami tidak akan menunggu 60 saat, tetapi akan segera mencetak 'Terganggu'. Ini kerana kami memanggil kaedah benang interrupt. Kaedah ini menetapkan "bendera dalaman dipanggil status gangguan". Iaitu, setiap utas mempunyai bendera dalaman yang tidak boleh diakses secara langsung. Tetapi kami mempunyai kaedah asli untuk berinteraksi dengan bendera ini. Tetapi ini bukan satu-satunya cara. Benang boleh dalam proses pelaksanaan, tidak menunggu sesuatu, tetapi hanya melakukan tindakan. Tetapi ia boleh memberikan bahawa mereka akan mahu menyelesaikannya pada titik tertentu dalam kerjanya. Sebagai contoh:
public static void main(String []args) {
	Runnable task = () -> {
		while(!Thread.currentThread().isInterrupted()) {
			//Do some work
		}
		System.out.println("Finished");
	};
	Thread thread = new Thread(task);
	thread.start();
	thread.interrupt();
}
Dalam contoh di atas, anda dapat melihat bahawa gelung whileakan berjalan sehingga benang terganggu secara luaran. Perkara penting yang perlu diketahui tentang bendera isInterrupted ialah jika kita menangkapnya InterruptedException, bendera itu isInterruptedditetapkan semula, dan kemudian isInterruptedia akan kembali palsu. Terdapat juga kaedah statik dalam kelas Thread yang hanya digunakan pada thread semasa - Thread.interrupted() , tetapi kaedah ini menetapkan semula bendera kepada false! Anda boleh membaca lebih lanjut dalam bab " Gangguan Benang ".

Sertai — Menunggu urutan lain selesai

Jenis menunggu yang paling mudah ialah menunggu urutan lain selesai.
public static void main(String []args) throws InterruptedException {
	Runnable task = () -> {
		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			System.out.println("Interrupted");
		}
	};
	Thread thread = new Thread(task);
	thread.start();
	thread.join();
	System.out.println("Finished");
}
Dalam contoh ini, urutan baharu akan tidur selama 5 saat. Pada masa yang sama, benang utama akan menunggu sehingga benang tidur bangun dan menyelesaikan kerjanya. Jika anda melihat melalui JVisualVM, keadaan benang akan kelihatan seperti ini: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 4Terima kasih kepada alat pemantauan, anda boleh melihat apa yang berlaku dengan benang. Kaedah ini joinagak mudah, kerana ia hanyalah kaedah dengan kod java yang dilaksanakan waitsemasa benang yang dipanggil masih hidup. Sebaik sahaja benang mati (semasa penamatan), penantian ditamatkan. Itulah keseluruhan keajaiban kaedah join. Oleh itu, mari kita beralih ke bahagian yang paling menarik.

Pemantau Konsep

Dalam multithreading terdapat perkara seperti Monitor. Secara umum, perkataan monitor diterjemahkan daripada bahasa Latin sebagai "pengawas" atau "pengawas." Dalam rangka artikel ini, kami akan cuba mengingati intipatinya, dan bagi mereka yang mahu, saya meminta anda menyelami bahan dari pautan untuk butirannya. Mari kita mulakan perjalanan kita dengan spesifikasi bahasa Java, iaitu dengan JLS: " 17.1. Penyegerakan ". Ia mengatakan perkara berikut: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 5Ternyata untuk tujuan penyegerakan antara benang, Java menggunakan mekanisme tertentu yang dipanggil "Monitor". Setiap objek mempunyai monitor yang dikaitkan dengannya, dan benang boleh menguncinya atau membuka kuncinya. Seterusnya, kami akan menemui tutorial latihan di laman web Oracle: " Kunci Intrinsik dan Penyegerakan ". Tutorial ini menerangkan bahawa penyegerakan dalam Java dibina di sekeliling entiti dalaman yang dikenali sebagai kunci intrinsik atau kunci monitor. Selalunya kunci sedemikian hanya dipanggil "monitor". Kami juga melihat sekali lagi bahawa setiap objek di Jawa mempunyai kunci intrinsik yang dikaitkan dengannya. Anda boleh membaca " Java - Kunci Intrinsik dan Penyegerakan ". Seterusnya, adalah penting untuk memahami bagaimana objek dalam Java boleh dikaitkan dengan monitor. Setiap objek dalam Java mempunyai pengepala - sejenis metadata dalaman yang tidak tersedia kepada pengaturcara daripada kod, tetapi mesin maya perlu berfungsi dengan objek dengan betul. Pengepala objek termasuk MarkWord yang kelihatan seperti ini: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 6

https://edu.netbeans.org/contrib/slides/java-overview-and-java-se6.pdf

Artikel daripada Habr sangat berguna di sini: " Tetapi bagaimanakah multithreading berfungsi? Bahagian I: penyegerakan ." Pada artikel ini adalah bernilai menambah penerangan daripada Ringkasan blok tugas daripada penyapih JDK: " JDK-8183909 ". Anda boleh membaca perkara yang sama dalam " JEP-8183909 ". Jadi, di Jawa, monitor dikaitkan dengan objek dan benang boleh menyekat benang ini, atau mereka juga mengatakan "dapatkan kunci". Contoh paling mudah:
public class HelloWorld{
    public static void main(String []args){
        Object object = new Object();
        synchronized(object) {
            System.out.println("Hello World");
        }
    }
}
Jadi, menggunakan kata kunci, synchronizedutas semasa (di mana baris kod ini dilaksanakan) cuba menggunakan monitor yang dikaitkan dengan objek objectdan "mendapatkan kunci" atau "menangkap monitor" (pilihan kedua adalah lebih baik). Jika tiada pertikaian untuk monitor (iaitu tiada orang lain yang mahu menyegerakkan pada objek yang sama), Java boleh cuba melakukan pengoptimuman yang dipanggil "penguncian berat sebelah". Tajuk objek dalam Mark Word akan mengandungi teg yang sepadan dan rekod benang mana monitor dilampirkan. Ini mengurangkan overhed apabila menangkap monitor. Sekiranya monitor telah diikat ke benang lain sebelum ini, maka penguncian ini tidak mencukupi. JVM bertukar kepada jenis penguncian seterusnya - penguncian asas. Ia menggunakan operasi bandingkan-dan-tukar (CAS). Pada masa yang sama, pengepala dalam Mark Word tidak lagi menyimpan Mark Word itu sendiri, tetapi pautan ke storannya + teg ditukar supaya JVM memahami bahawa kami menggunakan penguncian asas. Jika terdapat pertikaian untuk monitor beberapa utas (satu telah menangkap monitor, dan yang kedua sedang menunggu monitor dikeluarkan), maka teg dalam Mark Word berubah, dan Mark Word mula menyimpan rujukan kepada monitor sebagai objek - beberapa entiti dalaman JVM. Seperti yang dinyatakan dalam JEP, dalam kes ini, ruang diperlukan dalam kawasan memori Native Heap untuk menyimpan entiti ini. Pautan ke lokasi storan entiti dalaman ini akan terletak dalam objek Mark Word. Oleh itu, seperti yang kita lihat, monitor adalah benar-benar mekanisme untuk memastikan penyegerakan akses berbilang benang kepada sumber yang dikongsi. Terdapat beberapa pelaksanaan mekanisme ini yang JVM bertukar antara. Oleh itu, untuk kesederhanaan, apabila bercakap tentang monitor, kita sebenarnya bercakap tentang kunci. Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 7

Disegerakkan dan menunggu dengan kunci

Konsep monitor, seperti yang kita lihat sebelum ini, berkait rapat dengan konsep "blok penyegerakan" (atau, kerana ia juga dipanggil, bahagian kritikal). Mari lihat contoh:
public static void main(String[] args) throws InterruptedException {
	Object lock = new Object();

	Runnable task = () -> {
		synchronized (lock) {
			System.out.println("thread");
		}
	};

	Thread th1 = new Thread(task);
	th1.start();
	synchronized (lock) {
		for (int i = 0; i < 8; i++) {
			Thread.currentThread().sleep(1000);
			System.out.print("  " + i);
		}
		System.out.println(" ...");
	}
}
Di sini, utas utama mula-mula menghantar tugas ke utas baru, dan kemudian segera "menangkap" kunci dan melakukan operasi yang panjang dengannya (8 saat). Selama ini, tugas itu tidak boleh memasuki blok untuk pelaksanaannya synchronized, kerana kunci sudah diduduki. Jika benang tidak dapat memperoleh kunci, ia akan menunggu di monitor untuknya. Sebaik sahaja ia menerimanya, ia akan meneruskan pelaksanaan. Apabila benang meninggalkan monitor, ia melepaskan kunci. Dalam JVisualVM ia akan kelihatan seperti ini: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 8Seperti yang anda lihat, status dalam JVisualVM dipanggil "Monitor" kerana benang disekat dan tidak boleh menduduki monitor. Anda juga boleh mengetahui keadaan benang dalam kod, tetapi nama keadaan ini tidak bertepatan dengan istilah JVisualVM, walaupun ia serupa. Dalam kes ini, th1.getState()gelung forakan kembali BLOCKED , kerana Semasa gelung berjalan, monitor lockdiduduki mainoleh benang, dan benang th1disekat dan tidak boleh terus berfungsi sehingga kunci dikembalikan. Sebagai tambahan kepada blok penyegerakan, keseluruhan kaedah boleh disegerakkan. Sebagai contoh, kaedah dari kelas HashTable:
public synchronized int size() {
	return count;
}
Dalam satu unit masa, kaedah ini akan dilaksanakan oleh hanya satu utas. Tetapi kita memerlukan kunci, bukan? Ya saya perlukannya. Dalam kes kaedah objek, kunci akan this. Terdapat perbincangan menarik mengenai topik ini: " Adakah terdapat kelebihan untuk menggunakan Kaedah Disegerakkan dan bukannya Blok Disegerakkan? ". Jika kaedah statik, maka kunci tidak akan menjadi this(kerana untuk kaedah statik ia tidak boleh this), tetapi objek kelas (Sebagai contoh, Integer.class).

Tunggu dan tunggu di monitor. Kaedah memberitahu dan memberitahuSemua

Thread mempunyai kaedah tunggu lain, yang disambungkan ke monitor. Tidak seperti sleepdan join, ia tidak boleh dipanggil begitu sahaja. Dan namanya ialah wait. Kaedah ini dilaksanakan waitpada objek pada monitor yang kita mahu tunggu. Mari lihat contoh:
public static void main(String []args) throws InterruptedException {
	    Object lock = new Object();
	    // task будет ждать, пока его не оповестят через lock
	    Runnable task = () -> {
	        synchronized(lock) {
	            try {
	                lock.wait();
	            } catch(InterruptedException e) {
	                System.out.println("interrupted");
	            }
	        }
	        // После оповещения нас мы будем ждать, пока сможем взять лок
	        System.out.println("thread");
	    };
	    Thread taskThread = new Thread(task);
	    taskThread.start();
        // Ждём и после этого забираем себе лок, оповещаем и отдаём лок
	    Thread.currentThread().sleep(3000);
	    System.out.println("main");
	    synchronized(lock) {
	        lock.notify();
	    }
}
Dalam JVisualVM ia akan kelihatan seperti ini: Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 10Untuk memahami cara ini berfungsi, anda harus ingat bahawa kaedah waitmerujuk notifykepada java.lang.Object. Nampaknya pelik bahawa kaedah berkaitan benang berada dalam Object. Tetapi di sinilah jawapannya. Seperti yang kita ingat, setiap objek dalam Java mempunyai pengepala. Pengepala mengandungi pelbagai maklumat perkhidmatan, termasuk maklumat tentang monitor—data tentang keadaan penguncian. Dan seperti yang kita ingat, setiap objek (iaitu setiap contoh) mempunyai perkaitan dengan entiti JVM dalaman yang dipanggil kunci intrinsik, yang juga dipanggil monitor. Dalam contoh di atas, tugas itu menerangkan bahawa kita memasuki blok penyegerakan pada monitor yang dikaitkan dengan lock. Jika mungkin untuk mendapatkan kunci pada monitor ini, maka wait. Benang yang melaksanakan tugas ini akan melepaskan monitor lock, tetapi akan menyertai baris gilir benang yang menunggu pemberitahuan pada monitor lock. Barisan urutan ini dipanggil WAIT-SET, yang lebih tepat mencerminkan intipati. Ia lebih kepada satu set daripada barisan. Benang itu mainmencipta benang baharu dengan tugasan tugasan, memulakannya dan menunggu selama 3 saat. Ini membolehkan, dengan tahap kebarangkalian yang tinggi, benang baharu untuk mengambil kunci sebelum benang maindan beratur pada monitor. Selepas itu benang itu mainsendiri memasuki blok penyegerakan lockdan melakukan pemberitahuan benang pada monitor. Selepas pemberitahuan dihantar, utas mainmelepaskan monitor lock, dan utas baharu (yang sebelum ini menunggu) lockterus dilaksanakan selepas menunggu monitor dikeluarkan. Adalah mungkin untuk menghantar pemberitahuan kepada hanya satu daripada utas ( notify) atau kepada semua utas dalam baris gilir sekali gus ( notifyAll). Anda boleh membaca lebih lanjut dalam " Perbezaan antara notify() dan notifyAll() dalam Java ". Adalah penting untuk ambil perhatian bahawa susunan pemberitahuan bergantung pada pelaksanaan JVM. Anda boleh membaca lebih lanjut dalam " Bagaimana untuk menyelesaikan kebuluran dengan memberitahu dan memberitahu semua? ". Penyegerakan boleh dilakukan tanpa menentukan objek. Ini boleh dilakukan apabila bukan bahagian kod yang berasingan disegerakkan, tetapi keseluruhan kaedah. Sebagai contoh, untuk kaedah statik kunci akan menjadi objek kelas (diperolehi melalui .class):
public static synchronized void printA() {
	System.out.println("A");
}
public static void printB() {
	synchronized(HelloWorld.class) {
		System.out.println("B");
	}
}
Dari segi penggunaan kunci, kedua-dua kaedah adalah sama. Jika kaedah tersebut tidak statik, maka penyegerakan akan dilakukan mengikut arus instance, iaitu mengikut this. Ngomong-ngomong, sebelum ini kami mengatakan bahawa menggunakan kaedah itu getStateanda boleh mendapatkan status benang. Oleh itu, berikut adalah urutan yang beratur oleh monitor, statusnya akan MENUNGGU atau TIMED_WAITING jika kaedah waitmenetapkan had masa menunggu. Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 11

Kitaran hayat benang

Seperti yang kita lihat, aliran berubah statusnya dalam perjalanan kehidupan. Pada dasarnya, perubahan ini adalah kitaran hayat benang. Apabila benang baru dibuat, ia mempunyai status BARU. Dalam kedudukan ini, ia belum bermula dan Java Thread Scheduler belum mengetahui apa-apa tentang thread baru. Untuk penjadual benang mengetahui tentang benang, anda mesti memanggil thread.start(). Kemudian benang akan masuk ke keadaan RUNNABLE. Terdapat banyak skim yang tidak betul di Internet di mana keadaan Runnable dan Running dipisahkan. Tetapi ini adalah kesilapan, kerana... Java tidak membezakan antara status "sedia untuk dijalankan" dan "berjalan". Apabila benang hidup tetapi tidak aktif (tidak Boleh Dijalankan), ia berada dalam salah satu daripada dua keadaan:
  • DISEKAT - menunggu kemasukan ke bahagian yang dilindungi, i.e. ke synchonizedblok.
  • MENUNGGU - menunggu thread lain berdasarkan syarat. Jika keadaan itu benar, penjadual benang memulakan benang.
Jika urutan menunggu mengikut masa, ia berada dalam keadaan TIMED_WAITING. Jika utas tidak lagi berjalan (berjaya disiapkan atau dengan pengecualian), ia masuk ke status TERMINAT. Untuk mengetahui keadaan benang (keadaannya), kaedah digunakan getState. Benang juga mempunyai kaedah isAliveyang mengembalikan benar jika utas tidak Ditamatkan.

LockSokongan dan letak benang

Sejak Java 1.6 terdapat mekanisme menarik yang dipanggil LockSupport . Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 12Kelas ini mengaitkan "permit" atau kebenaran dengan setiap urutan yang menggunakannya. Panggilan kaedah parkkembali serta-merta jika permit tersedia, menduduki permit yang sama semasa panggilan. Jika tidak ia disekat. Memanggil kaedah unparkmembuat permit tersedia jika ia belum tersedia. Hanya terdapat 1 Permit. Dalam Java API , LockSupport. SemaphoreMari lihat contoh mudah:
import java.util.concurrent.Semaphore;
public class HelloWorldApp{

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(0);
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            // Просим разрешение и ждём, пока не получим его
            e.printStackTrace();
        }
        System.out.println("Hello, World!");
    }
}
Kod ini akan menunggu selama-lamanya kerana semafor kini mempunyai 0 permit. Dan apabila dipanggil dalam kod acquire(iaitu, minta kebenaran), utas menunggu sehingga ia menerima kebenaran. Memandangkan kami sedang menunggu, kami diwajibkan untuk memprosesnya InterruptedException. Menariknya, semaphore melaksanakan keadaan benang yang berasingan. Jika kita melihat dalam JVisualVM, kita akan melihat bahawa negeri kita bukanlah Tunggu, tetapi Park. Anda tidak boleh merosakkan Java dengan benang: Bahagian II - penyegerakan - 13Mari lihat contoh lain:
public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            //Запаркуем текущий поток
            System.err.println("Will be Parked");
            LockSupport.park();
            // Как только нас распаркуют - начнём действовать
            System.err.println("Unparked");
        };
        Thread th = new Thread(task);
        th.start();
        Thread.currentThread().sleep(2000);
        System.err.println("Thread state: " + th.getState());

        LockSupport.unpark(th);
        Thread.currentThread().sleep(2000);
}
Status urutan akan MENUNGGU, tetapi JVisualVM membezakan waitantara dari synchronizeddan parkdari LockSupport. Mengapa yang ini sangat penting LockSupport? Mari beralih lagi ke Java API dan lihat Thread State WAITING . Seperti yang anda lihat, terdapat hanya tiga cara untuk masuk ke dalamnya. 2 cara - ini waitdan join. Dan yang ketiga ialah LockSupport. Kunci dalam Java dibina berdasarkan prinsip yang sama LockSupportdan mewakili alat peringkat lebih tinggi. Jom cuba guna satu. Mari lihat, sebagai contoh, di ReentrantLock:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class HelloWorld{

    public static void main(String []args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        Runnable task = () -> {
            lock.lock();
            System.out.println("Thread");
            lock.unlock();
        };
        lock.lock();

        Thread th = new Thread(task);
        th.start();
        System.out.println("main");
        Thread.currentThread().sleep(2000);
        lock.unlock();
    }
}
Seperti dalam contoh sebelumnya, semuanya mudah di sini. lockmenunggu seseorang mengeluarkan sumber. Jika kita melihat dalam JVisualVM, kita akan melihat bahawa utas baharu akan diletak sehingga mainutas itu menguncinya. Anda boleh membaca lebih lanjut tentang kunci di sini: " Pengaturcaraan berbilang benang dalam Java 8. Bahagian dua. Menyegerakkan akses kepada objek boleh ubah " dan " Java Lock API. Teori dan contoh penggunaan ." Untuk lebih memahami pelaksanaan kunci, adalah berguna untuk membaca tentang Phazer dalam gambaran keseluruhan " Kelas Phaser ". Dan bercakap tentang pelbagai penyegerak, anda mesti membaca artikel tentang Habré “ Java.util.concurrent.* Synchronizers Reference ”.

Jumlah

Dalam ulasan ini, kami melihat cara utama benang berinteraksi di Jawa. Bahan tambahan: #Viacheslav
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION