JavaRush /Java Blog /Random-ID /Anda Tidak Dapat Memanjakan Java dengan Thread: Bagian I ...
Viacheslav
Level 3

Anda Tidak Dapat Memanjakan Java dengan Thread: Bagian I - Threads

Dipublikasikan di grup Random-ID

Perkenalan

Multithreading telah dibangun di Java sejak awal. Jadi mari kita lihat sekilas apa yang dimaksud dengan multithreading. Anda tidak dapat merusak Java dengan Thread: Bagian I - Threads - 1Mari kita ambil pelajaran resmi dari Oracle sebagai titik awal: " Pelajaran: Aplikasi "Halo Dunia!" ". Mari kita ubah sedikit kode aplikasi Hello World kita menjadi berikut ini:
class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsadalah larik parameter masukan yang diteruskan saat program dimulai. Mari kita simpan kode ini ke file dengan nama yang sesuai dengan nama kelas dan ekstensinya .java. Mari kita kompilasi menggunakan utilitas javac : javac HelloWorldApp.java Setelah itu, panggil kode kita dengan beberapa parameter, misalnya Roger: java HelloWorldApp Roger Anda tidak dapat merusak Java dengan Thread: Bagian I - Threads - 2Kode kita sekarang memiliki cacat serius. Jika kita tidak memberikan argumen apa pun (yaitu jalankan saja java HelloWorldApp), kita akan mendapatkan kesalahan:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
Pengecualian (yaitu kesalahan) terjadi di thread bernama main. Ternyata ada semacam thread di jawa? Di sinilah perjalanan kita dimulai.

Java dan utas

Untuk memahami apa itu thread, Anda perlu memahami bagaimana aplikasi Java diluncurkan. Mari kita ubah kode kita sebagai berikut:
class HelloWorldApp {
    public static void main(String[] args) {
		while (true) {
			//Do nothing
		}
	}
}
Sekarang mari kita kompilasi lagi menggunakan javac. Selanjutnya, untuk kenyamanan, kita akan menjalankan kode Java di jendela terpisah. Di Windows Anda dapat melakukan ini seperti ini: start java HelloWorldApp. Sekarang, dengan menggunakan utilitas jps , mari kita lihat informasi apa yang akan diberitahukan Java kepada kita: Anda tidak dapat merusak Java dengan Thread: Bagian I - Threads - 3Nomor pertama adalah PID atau ID Proses, pengidentifikasi proses. Apa itu proses?
Процесс — это совокупность codeа и данных, разделяющих общее виртуальное addressное пространство.
Dengan bantuan proses, eksekusi berbagai program diisolasi satu sama lain: setiap aplikasi menggunakan area memorinya sendiri tanpa mengganggu program lain. Saya menyarankan Anda untuk membaca artikel lebih detail: " https://habr.com/post/164487/ ". Suatu proses tidak bisa ada tanpa thread, jadi jika suatu proses ada, setidaknya ada satu thread di dalamnya. Bagaimana hal ini bisa terjadi di Jawa? Saat kita menjalankan program Java, eksekusinya dimulai dengan file main. Kita semacam masuk ke dalam programnya, jadi cara khusus ini maindisebut entry point, atau "entry point". Metodenya mainharus selalu public static voidagar Java Virtual Machine (JVM) bisa mulai mengeksekusi program kita. Lihat " Mengapa metode utama Java statis? " untuk lebih jelasnya. Ternyata peluncur java (java.exe atau javaw.exe) adalah aplikasi sederhana (aplikasi C sederhana): ia memuat berbagai DLL, yang sebenarnya merupakan JVM. Peluncur Java membuat serangkaian panggilan Java Native Interface (JNI) tertentu. JNI adalah mekanisme yang menjembatani dunia Java Virtual Machine dan dunia C++. Ternyata peluncurnya bukan JVM, melainkan pemuatnya. Ia mengetahui perintah yang benar untuk dijalankan untuk memulai JVM. Tahu cara mengatur semua lingkungan yang diperlukan menggunakan panggilan JNI. Pengorganisasian lingkungan ini juga mencakup pembuatan thread utama, yang biasa disebut main. Untuk lebih jelas melihat thread apa yang hidup dalam proses java, kami menggunakan program jvisualvm , yang disertakan dalam JDK. Mengetahui pid suatu proses, kita dapat membuka data di dalamnya dengan segera: jvisualvm --openpid айдипроцесса Anda tidak dapat merusak Java dengan Thread: Bagian I - Threads - 4Menariknya, setiap thread memiliki area tersendiri di memori yang dialokasikan untuk proses tersebut. Struktur memori ini disebut tumpukan. Tumpukan terdiri dari bingkai. Bingkai adalah titik pemanggilan suatu metode, titik eksekusi. Sebuah bingkai juga dapat direpresentasikan sebagai StackTraceElement (lihat Java API untuk StackTraceElement ). Anda dapat membaca lebih lanjut tentang memori yang dialokasikan untuk setiap thread di sini . Jika kita melihat Java API dan mencari kata Thread, kita akan melihat bahwa ada kelas java.lang.Thread . Kelas inilah yang mewakili aliran di Java, dan dengan inilah kita harus bekerja. Anda tidak dapat merusak Java dengan Thread: Bagian I - Threads - 5

java.lang.Utas

Sebuah thread di Java direpresentasikan sebagai turunan dari kelas java.lang.Thread. Perlu segera dipahami bahwa instance kelas Thread di Java bukanlah thread itu sendiri. Ini hanyalah sejenis API untuk thread tingkat rendah yang dikelola oleh JVM dan sistem operasi. Saat kami meluncurkan JVM menggunakan peluncur java, ini membuat thread utama dengan nama maindan beberapa thread layanan lainnya. Sebagaimana dinyatakan dalam JavaDoc kelas Thread: When a Java Virtual Machine starts up, there is usually a single non-daemon thread Ada 2 jenis thread: daemon dan non-daemon. Utas daemon adalah utas latar belakang (utas layanan) yang melakukan beberapa pekerjaan di latar belakang. Istilah menarik ini mengacu pada “Iblis Maxwell”, yang dapat Anda baca lebih lanjut di artikel Wikipedia tentang “ iblis ”. Sebagaimana dinyatakan dalam dokumentasi, JVM terus menjalankan program (proses) hingga:
  • Metode Runtime.exit tidak dipanggil
  • Semua thread non-daemon menyelesaikan pekerjaannya (tanpa kesalahan dan dengan pengecualian)
Oleh karena itu, detail penting: utas daemon dapat dihentikan pada perintah apa pun yang dijalankan. Oleh karena itu, integritas data di dalamnya tidak terjamin. Oleh karena itu, thread daemon cocok untuk beberapa tugas layanan. Misalnya saja di Java terdapat thread yang bertanggung jawab untuk memproses metode finalisasi atau thread yang berhubungan dengan Garbage Collector (GC). Setiap utas milik beberapa grup ( ThreadGroup ). Dan kelompok dapat masuk ke dalam satu sama lain, membentuk hierarki atau struktur tertentu.
public static void main(String []args){
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
Grup memungkinkan Anda menyederhanakan pengelolaan aliran dan melacaknya. Selain grup, thread memiliki pengendali pengecualiannya sendiri. Mari kita lihat sebuah contoh:
public static void main(String []args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
Pembagian dengan nol akan menimbulkan error yang ditangkap oleh handler. Jika Anda tidak menentukan sendiri handlernya, implementasi handler default akan berfungsi, yang akan menampilkan tumpukan kesalahan di StdError. Anda dapat membaca lebih lanjut di ulasan http://pro-java.ru/java-dlya-opytnyx/obrabotchik-neperexvachennyx-isklyuchenij-java/ ". Selain itu, utas memiliki prioritas. Anda dapat membaca lebih lanjut tentang prioritas di artikel " Prioritas Thread Java di Multithreading ".

Membuat utas

Sebagaimana dinyatakan dalam dokumentasi, kami memiliki 2 cara untuk membuat thread. Yang pertama adalah menciptakan ahli waris Anda. Misalnya:
public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");
        }
    }

    public static void main(String []args){
        Thread thread = new MyThread();
        thread.start();
    }
}
Seperti yang Anda lihat, tugas diluncurkan dalam metode run, dan thread diluncurkan dalam metode start. Mereka tidak perlu bingung, karena... jika kita menjalankan metode ini runsecara langsung, tidak ada thread baru yang akan dimulai. Ini adalah metode startyang meminta JVM untuk membuat thread baru. Opsi dengan turunan dari Thread buruk karena kami menyertakan Thread dalam hierarki kelas. Kerugian yang kedua adalah kita mulai melanggar prinsip “Tanggung Jawab Tunggal” SOLID, karena kelas kita secara bersamaan bertanggung jawab untuk mengelola thread dan beberapa tugas yang harus dilakukan di thread ini. Yang mana yang benar? Jawabannya ada pada metode runyang kita timpa:
public void run() {
	if (target != null) {
		target.run();
	}
}
Berikut targetini beberapa java.lang.Runnable, yang bisa kita teruskan ke Thread saat membuat instance kelas. Oleh karena itu, kita dapat melakukan ini:
public class HelloWorld{
    public static void main(String []args){
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            }
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Ini juga Runnablemerupakan antarmuka fungsional sejak Java 1.8. Ini memungkinkan Anda menulis kode tugas untuk thread dengan lebih indah:
public static void main(String []args){
	Runnable task = () -> {
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

Total

Jadi, saya berharap dari cerita ini jelas apa itu aliran, bagaimana aliran itu ada, dan operasi dasar apa yang dapat dilakukan dengannya. Pada bagian selanjutnya , ada baiknya memahami bagaimana thread berinteraksi satu sama lain dan bagaimana siklus hidupnya. #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION