제이온

[Spring] Cara Menggunakan @Async

  • Bahasa Penulisan: Bahasa Korea
  • Negara Standar: Semua Negaracountry-flag
  • TI

Dibuat: 2024-04-25

Dibuat: 2024-04-25 22:33

Penanganan Asynchronous Java

Sebelum melihat Spring @Async, konsep sinkron, asinkron, dan multi-threading itu penting. Diasumsikan Anda memahami konsep-konsep tersebut, dan mari kita lihat cara penanganan asinkron Java murni melalui kode. Jika Anda sudah terbiasa dengan thread Java, Anda dapat melewati bab ini.



Jika Anda membuat fungsi untuk menerima message dan hanya menampilkannya dengan cara sinkron, Anda dapat menulis kode seperti di atas. Mengubahnya menjadi metode asinkron multi-threading, Anda dapat menulis kode sumber seperti berikut.



Namun, metode ini sangat berbahaya karena Anda tidak dapat mengelola Thread. Misalnya, jika ada 10.000 panggilan secara bersamaan, Anda harus membuat 10.000 Thread dalam waktu yang sangat singkat. Biaya pembuatan Thread tidaklah sedikit, sehingga berdampak buruk pada kinerja program, dan bahkan dapat menyebabkan error OOM. Oleh karena itu, Anda perlu mengimplementasikan Thread Pool untuk mengelola Thread, dan Java menyediakan kelas ExecutorService.



Jumlah total Thread dibatasi menjadi 10, dan kita dapat melakukan penanganan asinkron dengan cara multi-threading yang kita inginkan dengan benar. Namun, metode di atas mengharuskan Anda menerapkan metode submit() dari ExecutorService untuk setiap metode yang ingin Anda tangani secara asinkron, sehingga Anda perlu melakukan pekerjaan modifikasi yang berulang. Dengan kata lain, jika Anda ingin mengubah metode yang awalnya ditulis dengan logika sinkron menjadi asinkron, Anda harus mengubah logika metode itu sendiri.


Spring @Async

Metode Sederhana


Cukup tambahkan anotasi @EnableAsync di atas kelas Application, dan tambahkan anotasi @Async di atas metode logika sinkron yang ingin Anda tangani secara asinkron. Namun, metode di atas memiliki masalah dalam hal tidak mengelola thread. Karena konfigurasi default @Async adalah menggunakan SimpleAsyncTaskExecutor, yang bukan thread pool dan hanya berfungsi untuk membuat thread.


Menggunakan Thread Pool

Pertama, hapus @EnableAsync dari kelas Application. Jika kelas Application memiliki konfigurasi @EnableAutoConfiguration atau @SpringBootApplication, itu karena pada saat runtime, informasi bean threadPoolTaskExecutor (yang akan kita buat nanti) dari kelas SpringAsyncConfig (yang dikonfigurasi) akan dibaca.



Anda dapat mengatur ukuran inti dan maksimum. Pada saat itu, Anda mungkin berharap bahwa itu akan beroperasi dengan jumlah inti awal, dan jika tidak dapat menangani pekerjaan lebih lanjut, jumlah thread akan meningkat hingga jumlah maksimum, tetapi tidak demikian.


Secara internal, ia membuat LinkedBlockingQueue dengan ukuran Integer.MAX_VALUE, dan jika thread dengan ukuran inti tidak dapat menangani pekerjaan, mereka akan menunggu dalam antrean. Jika antrean penuh, maka thread dengan ukuran maksimum akan dibuat untuk menangani pekerjaan.


Pada saat itu, jika Anda merasa tidak nyaman mengatur ukuran antrean ke Integer.MAX_VALUE, Anda dapat mengatur queueCapacity. Dengan pengaturan seperti di atas, ia akan mulai dengan 3 thread, dan jika kecepatan pemrosesan melambat, pekerjaan akan dimasukkan ke dalam antrean dengan ukuran 100, dan jika ada lebih banyak permintaan, ia akan membuat hingga 30 thread untuk menangani pekerjaan.


Setelah konfigurasi thread pool selesai, Anda dapat melampirkan nama bean di metode yang memiliki anotasi @Async.



Jika Anda ingin mengatur beberapa jenis thread pool, Anda dapat membuat beberapa metode pembuatan bean seperti threadPoolTaskExecutor(), dan saat mengatur @Async, Anda dapat memasukkan bean thread pool yang Anda inginkan.


Bentuk yang Dikembalikan Berdasarkan Tipe Pengembalian

Tidak Ada Nilai Pengembalian

Ini adalah kasus di mana metode yang perlu ditangani secara asinkron tidak perlu mengirimkan hasil pemrosesan. Dalam kasus ini, Anda dapat mengatur tipe pengembalian anotasi @Async ke void.


Ada Nilai Pengembalian

Anda dapat menggunakan tipe Future, ListenableFuture, dan CompletableFuture sebagai tipe pengembalian. Bentuk pengembalian dari metode asinkron dapat dibungkus dengan new AsyncResult().


[Future]


future.get() berfungsi untuk menunggu hingga hasil permintaan datang melalui pemblokiran. Jadi, itu menjadi metode pemblokiran asinkron, yang tidak efisien. Biasanya, Future tidak digunakan.


[ListenableFuture]


ListenableFuture memungkinkan Anda untuk menangani pekerjaan dengan cara non-blocking melalui callback. Pada metode addCallback(), parameter pertama mendefinisikan metode callback penyelesaian pekerjaan, dan parameter kedua mendefinisikan metode callback kesalahan pekerjaan. Sebagai referensi, karena jumlah thread inti dari thread pool diatur ke 3, Anda dapat melihat bahwa pesan "Task Start" dicetak 3 kali di awal.



[CompletableFuture]

Meskipun Anda dapat mengimplementasikan logika non-blocking hanya dengan ListenableFuture, jika Anda memerlukan callback di dalam callback, itu akan menyebabkan kode yang sangat kompleks yang disebut callback hell.


<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9f152db8-c015-43cd-bf13-85c594f5f218%2FUntitled.png?table=block&id=268ac0bc-ca7b-4bcb-b11b-ac611a5038b2&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/1455;" width="2000" height="1455"></span>


Tentu saja, karena kita tidak akan membahas CompletableFuture secara detail kali ini, jika Anda penasaran dengan kode yang menangani callback yang kompleks, silakan lihat tautan sumber di bawah ini.



Ini memiliki keterbacaan yang lebih baik daripada definisi callback ListenableFuture, dan sepenuhnya melakukan fungsi non-blocking. Oleh karena itu, disarankan untuk menggunakan CompletableFuture saat menggunakan @Async dan memerlukan nilai pengembalian.


Keuntungan @Async

Pengembang dapat menulis metode dengan cara sinkron, dan jika mereka menginginkan metode asinkron, mereka hanya perlu menambahkan anotasi @Async di atas metode tersebut. Dengan demikian, Anda dapat membuat kode yang mudah dipelihara untuk sinkron dan asinkron.


Hal yang Perlu Diperhatikan pada @Async

Untuk menggunakan fungsi @Async, Anda perlu mendeklarasikan anotasi @EnableAsync, tetapi jika Anda tidak melakukan konfigurasi khusus, ia akan beroperasi dalam mode proxy. Dengan kata lain, semua metode asinkron yang beroperasi dengan anotasi @Async akan mengikuti batasan Spring AOP. Untuk alasan yang lebih rinci, silakan lihat postingan ini.


  • Meskipun Anda melampirkan @Async ke metode private, AOP tidak akan berfungsi.
  • Saat memanggil antar metode dalam objek yang sama, AOP tidak akan berfungsi.


Sumber

Komentar0