CodeGym /Java Blog /Acak /Lebih baik bersama: Java dan kelas Thread. Bagian I — Uta...
John Squirrels
Level 41
San Francisco

Lebih baik bersama: Java dan kelas Thread. Bagian I — Utas eksekusi

Dipublikasikan di grup Acak

Perkenalan

Multithreading dibangun ke dalam Java sejak awal. Jadi, mari kita lihat secara singkat hal yang disebut multithreading ini. Lebih baik bersama: Java dan kelas Thread.  Bagian I — Utas eksekusi - 1Kami mengambil pelajaran resmi dari Oracle sebagai referensi: " Pelajaran: Aplikasi "Halo Dunia!" ". Kami akan sedikit mengubah kode program Hello World kami sebagai berikut:

class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsadalah larik parameter masukan yang diteruskan saat program dimulai. Simpan kode ini ke file dengan nama yang sesuai dengan nama kelas dan memiliki ekstensi .java. Kompilasi menggunakan utilitas javac : javac HelloWorldApp.java. Kemudian, kami menjalankan kode kami dengan beberapa parameter, misalnya, "Roger": java HelloWorldApp Roger Lebih baik bersama: Java dan kelas Thread.  Bagian I — Utas eksekusi - 2Kode kami saat ini memiliki cacat serius. Jika Anda tidak memberikan argumen apa pun (mis. jalankan saja "java HelloWorldApp"), maka kami mendapatkan kesalahan:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
Pengecualian (yaitu kesalahan) terjadi di utas bernama "main". Jadi, Java punya utas? Disinilah perjalanan kita dimulai.

Jawa dan benang

Untuk memahami apa itu utas, Anda perlu memahami bagaimana program Java dimulai. Mari ubah kode kita sebagai berikut:

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
Sekarang mari kita kompilasi lagi dengan javac. Untuk kenyamanan, kami akan menjalankan kode Java kami di jendela terpisah. Di Windows, ini bisa dilakukan seperti ini: start java HelloWorldApp. Sekarang kita akan menggunakan utilitas jps untuk melihat informasi apa yang dapat diberikan Java kepada kita: Lebih baik bersama: Java dan kelas Thread.  Bagian I — Utas eksekusi - 3Angka pertama adalah PID atau ID Proses. Apa itu proses?

A process is a combination of code and data sharing a common virtual address space.
Dengan proses, program yang berbeda diisolasi satu sama lain saat dijalankan: setiap aplikasi menggunakan areanya sendiri di memori tanpa mengganggu program lain. Untuk mempelajari lebih lanjut, saya sarankan membaca tutorial ini: Processes and Threads . Suatu proses tidak dapat ada tanpa thread, jadi jika suatu proses ada, maka proses tersebut memiliki setidaknya satu thread. Tapi bagaimana ini terjadi di Jawa? Saat kita memulai program Java, eksekusi dimulai dengan mainmetode. Seolah-olah kita sedang melangkah ke dalam program, jadi mainmetode khusus ini disebut titik masuk. Metodenya mainharus selalu "public static void", sehingga mesin virtual Java (JVM) dapat mulai menjalankan program kita. Untuk informasi lebih lanjut, Mengapa metode utama Java statis?. Ternyata peluncur Java (java.exe atau javaw.exe) adalah aplikasi C sederhana: ini memuat berbagai DLL yang sebenarnya terdiri dari JVM. Peluncur Java membuat serangkaian panggilan Java Native Interface (JNI) tertentu. JNI adalah mekanisme untuk menghubungkan dunia mesin virtual Java dengan dunia C++. Jadi, launcher bukanlah JVM itu sendiri, melainkan sebuah mekanisme untuk memuatnya. Ia tahu perintah yang benar untuk dijalankan untuk memulai JVM. Ia tahu cara menggunakan panggilan JNI untuk menyiapkan lingkungan yang diperlukan. Menyiapkan lingkungan ini termasuk membuat utas utama, yang tentu saja disebut "utama". Untuk mengilustrasikan utas mana yang ada dalam proses Java dengan lebih baik, kami menggunakan jvisualvmalat, yang disertakan dengan JDK. Mengetahui pid suatu proses, kita dapat segera melihat informasi tentang proses itu: jvisualvm --openpid <process id> Lebih baik bersama: Java dan kelas Thread.  Bagian I — Utas eksekusi - 4Menariknya, setiap utas memiliki area tersendiri dalam memori yang dialokasikan untuk proses tersebut. Struktur memori ini disebut stack. Tumpukan terdiri dari bingkai. Bingkai mewakili aktivasi metode (panggilan metode yang belum selesai). Frame juga dapat direpresentasikan sebagai StackTraceElement (lihat API Java untuk StackTraceElement ). Anda dapat menemukan informasi lebih lanjut tentang memori yang dialokasikan untuk setiap utas dalam diskusi di sini: " Bagaimana Java (JVM) mengalokasikan tumpukan untuk setiap utas ". Jika Anda melihat Java API dan mencari kata "Thread", Anda akan menemukan java.lang.Threadkelas. Ini adalah kelas yang mewakili utas di Jawa, dan kita harus bekerja dengannya. Lebih baik bersama: Java dan kelas Thread.  Bagian I — Utas eksekusi - 5

java.lang.Thread

Di Jawa, sebuah utas diwakili oleh turunan dari kelas java.lang.Thread. Anda harus segera memahami bahwa instance dari kelas Thread itu sendiri bukanlah thread eksekusi. Ini hanyalah semacam API untuk utas tingkat rendah yang dikelola oleh JVM dan sistem operasi. Saat kita memulai JVM menggunakan peluncur Java, JVM membuat mainutas bernama "utama" dan beberapa utas housekeeping lainnya. Seperti yang dinyatakan dalam JavaDoc untuk kelas Thread: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. Ada 2 jenis utas: daemon dan non-daemon. Utas daemon adalah utas latar belakang (tata graha) yang melakukan beberapa pekerjaan di latar belakang. Kata "daemon" mengacu pada iblis Maxwell. Anda dapat mempelajari lebih lanjut di artikel Wikipedia ini . Sebagaimana dinyatakan dalam dokumentasi, JVM terus menjalankan program (proses) hingga:
  • Metode Runtime.exit () dipanggil
  • Semua utas NON-daemon menyelesaikan pekerjaannya (tanpa kesalahan atau dengan pengecualian yang dilemparkan)
Detail penting mengikuti dari ini: utas daemon dapat diakhiri kapan saja. Akibatnya, tidak ada jaminan tentang integritas data mereka. Karenanya, utas daemon cocok untuk tugas rumah tangga tertentu. Misalnya, Java memiliki utas yang bertanggung jawab untuk memproses pemanggilan finalize()metode, yaitu utas yang terkait dengan Garbage Collector (gc). Setiap utas adalah bagian dari grup ( ThreadGroup ). Dan kelompok dapat menjadi bagian dari kelompok 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 menertibkan manajemen utas. Selain grup, utas memiliki penangan pengecualiannya sendiri. Lihatlah 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 kesalahan yang akan ditangkap oleh pawang. Jika Anda tidak menentukan penangan Anda sendiri, maka JVM akan memanggil penangan default, yang akan menampilkan jejak tumpukan pengecualian ke StdError. Setiap utas juga memiliki prioritas. Anda dapat membaca lebih lanjut tentang prioritas di artikel ini: Java Thread Priority in Multithreading .

Membuat utas

Sebagaimana dinyatakan dalam dokumentasi, kami memiliki 2 cara untuk membuat utas. Cara pertama adalah membuat subclass Anda sendiri. 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, pekerjaan tugas terjadi di dalam run()metode, tetapi utas itu sendiri dimulai di dalam start()metode. Jangan bingung metode ini: jika kita memanggil un()metode r secara langsung, maka tidak ada utas baru yang akan dimulai. Ini adalah start()metode yang meminta JVM untuk membuat utas baru. Opsi di mana kita mewarisi Thread ini sudah buruk karena kita menyertakan Thread dalam hierarki kelas kita. Kelemahan kedua adalah kita mulai melanggar prinsip "tanggung jawab tunggal". Yaitu, kelas kami secara bersamaan bertanggung jawab untuk mengontrol utas dan untuk beberapa tugas yang harus dilakukan di utas ini. Apa cara yang benar? Jawabannya ditemukan dalam run()metode yang sama, yang kami timpa:

public void run() {
	if (target != null) {
		target.run();
	}
}
Di sini, targetada beberapa java.lang.Runnable, yang bisa kita lewati saat membuat instance dari kelas Thread. Ini berarti 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();
    }
}
Runnablejuga telah menjadi antarmuka fungsional sejak Java 1.8. Ini memungkinkan untuk menulis kode yang lebih indah untuk tugas utas:

public static void main(String[] args) {
	Runnable task = () -> { 
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

Kesimpulan

Saya harap diskusi ini menjelaskan apa itu utas, bagaimana utas muncul, dan operasi dasar apa yang dapat dilakukan dengan utas. Di bagian selanjutnya , kita akan mencoba memahami bagaimana utas berinteraksi satu sama lain dan menjelajahi siklus hidup utas. Lebih baik bersama: Java dan kelas Thread. Bagian II — Sinkronisasi Lebih baik bersama: Java dan kelas Thread. Bagian III — Interaksi Bersama yang lebih baik: Java dan kelas Thread. Bagian IV — Callable, Future, dan teman Lebih baik bersama: Java dan kelas Thread. Bagian V — Pelaksana, ThreadPool, Fork/Bergabung Lebih baik bersama-sama: Java dan kelas Thread. Bagian VI — Tembak!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION