OpenJDK Project Loom

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat Projek Loom dengan cepat. Pada hakikatnya, tujuan utama Project Loom adalah untuk menyokong model serentak tinggi, ringan dan ringkas di Jawa.

2. Projek Loom

Project Loom adalah percubaan oleh komuniti OpenJDK untuk memperkenalkan konstruk serentak ringan ke Java. Prototaip untuk Loom setakat ini telah memperkenalkan perubahan dalam JVM dan juga perpustakaan Java.

Walaupun belum ada rilis yang dijadualkan untuk Loom, kami dapat mengakses prototaip baru-baru ini di wiki Project Loom.

Sebelum kita membincangkan pelbagai konsep Loom, mari kita bincangkan model kesesuaian semasa di Jawa.

3. Model Kesesuaian Java

Pada masa ini, Thread melambangkan penghasilan inti konkurensi di Jawa. Pengabaian ini, bersama dengan API serentak yang lain memudahkan untuk menulis aplikasi serentak.

Namun, kerana Java menggunakan utas kernel OS untuk pelaksanaannya, ia gagal memenuhi keperluan serentak hari ini. Terdapat dua masalah utama khususnya:

  1. Thread tidak dapat menandingi skala unit serentak domain. Sebagai contoh, aplikasi biasanya membenarkan hingga berjuta-juta transaksi, pengguna atau sesi. Walau bagaimanapun, bilangan utas yang disokong oleh kernel jauh lebih sedikit. Oleh itu, rintangan T untuk setiap pengguna, transaksi, atau sesi sering tidak dapat dilaksanakan.
  2. Sebilangan besar aplikasi serentak memerlukan beberapa penyegerakan antara utas untuk setiap permintaan. Oleh kerana itu, pertukaran konteks yang mahal berlaku di antara utas OS.

Penyelesaian yang mungkin untuk masalah tersebut adalah penggunaan API serentak tak segerak . Contoh biasa ialah CompletableFuture dan RxJava. Dengan syarat bahawa API seperti itu tidak menyekat utas kernel, itu memberikan aplikasi konstruk serentak yang lebih halus di atas benang Java .

Sebaliknya, API seperti itu lebih sukar untuk debug dan disatukan dengan API lama . Oleh itu, terdapat keperluan untuk konstruk serentak ringan yang tidak bergantung pada benang kernel.

4. Tugas dan Penjadual

Sebarang pelaksanaan benang, sama ada ringan atau berat, bergantung pada dua konstruk:

  1. Tugas (juga dikenali sebagai kesinambungan) - Urutan arahan yang dapat menggantung dirinya sendiri untuk beberapa operasi penyekat
  2. Penjadual - Untuk menetapkan kelanjutan ke CPU dan menetapkan ulang CPU dari kelanjutan yang dijeda

Pada masa ini, Java bergantung pada implementasi OS untuk kesinambungan dan penjadual .

Sekarang, untuk menangguhkan kesinambungan, diperlukan untuk menyimpan keseluruhan timbunan panggilan. Begitu juga, dapatkan timbunan panggilan pada penyambungan semula. Oleh kerana pelaksanaan OS dari kesinambungan termasuk stack panggilan asli bersama dengan stack panggilan Java, ini menghasilkan jejak yang berat .

Masalah yang lebih besar adalah penggunaan penjadual OS. Oleh kerana penjadual berjalan dalam mod kernel, tidak ada perbezaan antara utas. Dan ia melayan setiap permintaan CPU dengan cara yang sama.

Penjadualan jenis ini tidak optimum untuk aplikasi Java khususnya .

Sebagai contoh, pertimbangkan utas aplikasi yang melakukan beberapa tindakan pada permintaan dan kemudian menyampaikan data ke utas lain untuk diproses lebih lanjut. Di sini, lebih baik menjadualkan kedua-dua utas ini pada CPU yang sama . Tetapi kerana penjadual adalah agnostik ke utas yang meminta CPU, ini mustahil untuk dijamin.

Project Loom mengusulkan untuk menyelesaikannya melalui utas mod pengguna yang bergantung pada penerapan Java untuk jangka masa dan penerapan penjadwalan dan bukannya pelaksanaan OS .

5. Serat

Dalam prototaip baru-baru ini di OpenJDK, kelas baru bernama Fiber diperkenalkan ke perpustakaan di samping kelas Thread .

Oleh kerana perpustakaan yang dirancang untuk Fibers serupa dengan Thread , pelaksanaan pengguna juga harus tetap serupa. Walau bagaimanapun, terdapat dua perbezaan utama:

  1. Fiber akan menyelesaikan tugas dalam kelanjutan mod pengguna dalaman. Ini akan memungkinkan tugas untuk menangguhkan dan menyambung semula dalam Java runtime dan bukannya kernel
  2. Penjadual mod pengguna yang boleh dipasang ( misalnya ForkJoinPool ) akan digunakan

Mari kita teliti dua perkara ini secara terperinci.

6. Kesinambungan

Kesinambungan (atau rutin bersama) adalah urutan arahan yang dapat menghasilkan dan dilanjutkan oleh pemanggil pada tahap selanjutnya.

Setiap kesinambungan mempunyai titik masuk dan titik hasil. Titik hasil adalah di mana ia ditangguhkan. Setiap kali pemanggil meneruskan kesinambungan, kawalan kembali ke titik hasil terakhir.

Penting untuk menyedari bahawa penangguhan / resume ini sekarang berlaku pada runtime bahasa dan bukannya OS . Oleh itu, ia menghalang pertukaran konteks yang mahal antara utas kernel.

Sama seperti benang, Project Loom bertujuan untuk menyokong gentian bersarang. Oleh kerana gentian bergantung pada kesinambungan secara dalaman, ia juga mesti menyokong kesinambungan bersarang. Untuk memahami perkara ini dengan lebih baik, pertimbangkan kelas Lanjutan yang membolehkan bersarang:

Continuation cont1 = new Continuation(() -> { Continuation cont2 = new Continuation(() -> { //do something suspend(SCOPE_CONT_2); suspend(SCOPE_CONT_1); }); });

Seperti yang ditunjukkan di atas, kesinambungan bersarang dapat menangguhkan dirinya sendiri atau salah satu kelanjutan yang dilampirkan dengan melewati pemboleh ubah skop . Atas sebab ini, mereka dikenal sebagai kesinambungan lingkup .

Oleh kerana menangguhkan kesinambungan juga memerlukannya untuk menyimpan timbunan panggilan, ini juga merupakan tujuan projek Loom untuk menambahkan pengambilan timbunan ringan sambil meneruskan penerusan.

7. Penjadual

Sebelumnya, kami membincangkan kekurangan penjadual OS dalam menjadwalkan utas yang berkaitan pada CPU yang sama.

Walaupun merupakan tujuan untuk Project Loom untuk membenarkan penjadual yang dapat dipasang dengan gentian, ForkJoinPool dalam mod asinkron akan digunakan sebagai penjadual lalai.

ForkJoinPool works on the work-stealing algorithm. Thus, every thread maintains a task deque and executes the task from its head. Furthermore, any idle thread does not block, waiting for the task and pulls it from the tail of another thread's deque instead.

The only difference in asynchronous mode is that the worker threads steal the task from the head of another deque.

ForkJoinPool adds a task scheduled by another running task to the local queue. Hence, executing it on the same CPU.

8. Conclusion

In this article, we discussed the problems in Java's current concurrency model and the changes proposed by Project Loom.

Dengan berbuat demikian, kami juga menentukan tugas dan penjadual dan melihat bagaimana Fibers dan ForkJoinPool dapat memberikan alternatif kepada Java menggunakan utas kernel.