OpenJDK Project Loom

1. Ikhtisar

Pada artikel ini, kita akan melihat sekilas Project Loom. Intinya, tujuan utama Project Loom adalah mendukung model konkurensi ringan dan throughput tinggi di Java.

2. Proyek Alat tenun

Project Loom adalah upaya komunitas OpenJDK untuk memperkenalkan konstruksi konkurensi ringan ke Java. Prototipe untuk Loom sejauh ini telah memperkenalkan perubahan pada JVM serta pustaka Java.

Meskipun belum ada rilis terjadwal untuk Loom, kami dapat mengakses prototipe terbaru di wiki Project Loom.

Sebelum kita membahas berbagai konsep Loom, mari kita bahas model konkurensi saat ini di Java.

3. Model Konkurensi Java

Saat ini, Thread mewakili abstraksi inti konkurensi di Java. Abstraksi ini, bersama dengan API konkuren lainnya memudahkan penulisan aplikasi serentak.

Namun, karena Java menggunakan utas kernel OS untuk implementasinya, Java gagal memenuhi persyaratan konkurensi saat ini. Ada dua masalah utama khususnya:

  1. Untaian tidak boleh cocok dengan skala unit domain konkurensi. Misalnya, aplikasi biasanya memungkinkan hingga jutaan transaksi, pengguna, atau sesi. Namun, jumlah utas yang didukung oleh kernel jauh lebih sedikit. Jadi, T hread untuk setiap pengguna, transaksi, atau sesi sering kali tidak layak.
  2. Sebagian besar aplikasi serentak memerlukan beberapa sinkronisasi antar utas untuk setiap permintaan. Karena itu, peralihan konteks yang mahal terjadi di antara utas OS.

Solusi yang mungkin untuk masalah tersebut adalah penggunaan API serentak asinkron . Contoh umum adalah CompletableFuture dan RxJava. Asalkan API semacam itu tidak memblokir utas kernel, ini memberi aplikasi konstruksi konkurensi yang lebih terperinci di atas utas Java .

Di sisi lain, API semacam itu lebih sulit untuk di-debug dan diintegrasikan dengan API lama . Dan dengan demikian, ada kebutuhan untuk konstruksi konkurensi ringan yang tidak bergantung pada utas kernel.

4. Tugas dan Penjadwal

Implementasi utas apa pun, baik ringan atau kelas berat, bergantung pada dua konstruksi:

  1. Tugas (juga dikenal sebagai kelanjutan) - Urutan instruksi yang dapat ditangguhkan sendiri untuk beberapa operasi pemblokiran
  2. Scheduler - Untuk menetapkan kelanjutan ke CPU dan menetapkan kembali CPU dari kelanjutan yang dijeda

Saat ini, Java mengandalkan implementasi OS untuk kelanjutan dan penjadwal .

Sekarang, untuk menangguhkan kelanjutan, itu diperlukan untuk menyimpan seluruh tumpukan panggilan. Demikian pula, ambil tumpukan panggilan saat dilanjutkan. Karena implementasi OS dari kelanjutan menyertakan stack panggilan asli bersama dengan stack panggilan Java, ini menghasilkan footprint yang berat .

Masalah yang lebih besar, bagaimanapun, adalah penggunaan penjadwal OS. Karena penjadwal berjalan dalam mode kernel, tidak ada perbedaan antara utas. Dan itu memperlakukan setiap permintaan CPU dengan cara yang sama.

Jenis penjadwalan ini tidak optimal khususnya untuk aplikasi Java .

Misalnya, pertimbangkan thread aplikasi yang melakukan beberapa tindakan pada permintaan dan kemudian meneruskan data ke thread lain untuk diproses lebih lanjut. Di sini, akan lebih baik untuk menjadwalkan kedua utas ini pada CPU yang sama . Tetapi karena penjadwal agnostik ke utas yang meminta CPU, hal ini tidak dapat dijamin.

Project Loom mengusulkan untuk menyelesaikan ini melalui utas mode pengguna yang mengandalkan implementasi runtime Java dari kelanjutan dan penjadwal, bukan implementasi OS .

5. Serat

Dalam prototipe terbaru di OpenJDK, kelas baru bernama Fiber diperkenalkan ke pustaka bersama kelas Thread .

Karena pustaka yang direncanakan untuk Serat mirip dengan Thread , implementasi pengguna juga harus tetap serupa. Namun, ada dua perbedaan utama:

  1. Fiber akan membungkus tugas apa pun dalam kelanjutan mode pengguna internal. Ini akan memungkinkan tugas untuk menangguhkan dan melanjutkan di runtime Java, bukan di kernel
  2. Penjadwal mode pengguna yang dapat dicolokkan ( ForkJoinPool, misalnya) akan digunakan

Mari kita bahas kedua item ini secara mendetail.

6. Lanjutan

Kelanjutan (atau rutin bersama) adalah urutan instruksi yang dapat menghasilkan dan dilanjutkan oleh pemanggil di tahap selanjutnya.

Setiap kelanjutan memiliki titik masuk dan titik hasil. Titik hasil di mana itu ditangguhkan. Setiap kali pemanggil melanjutkan kelanjutan, kontrol kembali ke titik hasil terakhir.

Penting untuk disadari bahwa penangguhan / resume ini sekarang terjadi di runtime bahasa, bukan di OS . Oleh karena itu, ini mencegah peralihan konteks yang mahal antara utas kernel.

Mirip dengan utas, Project Loom bertujuan untuk mendukung serat bersarang. Karena serat bergantung pada kelanjutan secara internal, itu juga harus mendukung kelanjutan bersarang. Untuk memahami ini lebih baik, pertimbangkan kelanjutan kelas yang memungkinkan penumpukan:

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

Seperti yang ditunjukkan di atas, kelanjutan bersarang bisa menangguhkan dirinya sendiri atau kelanjutan yang melingkupi dengan meneruskan variabel lingkup . Untuk alasan ini, mereka dikenal sebagai kelanjutan cakupan .

Karena menangguhkan kelanjutan juga akan mengharuskannya untuk menyimpan tumpukan panggilan, itu juga merupakan tujuan proyek Loom untuk menambahkan pengambilan tumpukan ringan sambil melanjutkan kelanjutan.

7. Penjadwal

Sebelumnya, kita telah membahas kekurangan dari OS scheduler dalam menjadwalkan thread yang dapat dihubungkan pada CPU yang sama.

Meskipun merupakan tujuan Project Loom untuk memungkinkan penjadwal yang dapat dicolokkan dengan serat, ForkJoinPool dalam mode asinkron akan digunakan sebagai penjadwal default.

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.

Dalam melakukannya, kami juga mendefinisikan tugas dan penjadwal dan melihat bagaimana Fibers dan ForkJoinPool dapat memberikan alternatif untuk Java menggunakan utas kernel.