Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Çıkış Yap

translation

Bu, AI tarafından çevrilen bir gönderidir.

제이온

[Spring] @Async kullanımı

  • tr Writing language: Korece
  • tr Referans Ülke: tr Tüm ülkeler country-flag

Dil Seç

  • Türkçe
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Text summarized by durumis AI

  • Java eşzamansız işlemlerini Spring @Async kullanarak uygulama yöntemini, avantajlarını ve dikkat edilmesi gereken noktaları açıklar.
  • Spring @Async'yi kullanarak @EnableAsync anotasyonunu ekleyerek ve eşzamansız işlem yapılmasını istediğiniz metotlara @Async anotasyonunu ekleyerek eşzamansız işlemleri kolayca uygulayabilirsiniz.
  • İş parçacığı havuzu ayarlarıyla etkili iş parçacığı yönetimi sağlanabilir ve dönüş tipiyle Future, ListenableFuture ve CompletableFuture gibi yapıları kullanarak eşzamansız işlem sonuçları döndürülebilir.

Java Asenkron İşleme

Spring @Async'i incelemeden önce, senkron, asenkron ve çoklu iş parçacığı kavramları çok önemlidir. Bu kavramları bildiğinizi varsayarak, yalnızca Java asenkron işleme yöntemini kod olarak inceleyelim. Eğer Java iş parçacıklarıyla zaten aşinasanız, bu bölümü geçebilirsiniz.


public class MessageService {

    public void print(String message) {
        System.out.println(message);
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Eğer bir mesaj alıp sadece yazdırma işlevi senkron bir şekilde yapılırsa, yukarıdaki gibi kod yazabilirsiniz. Bunu çoklu iş parçacığı asenkron yöntemine dönüştürürsek, kaynak kodunu aşağıdaki gibi yazabiliriz.


public class MessageService {

    public void print(String message) {
        new Thread(() -> System.out.println(message))
                .start();
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Ancak bu yöntem, iş parçacıklarını yönetemediğimiz için çok tehlikelidir. Örneğin, aynı anda 10.000 çağrı yapılırsa, çok kısa bir sürede 10.000 iş parçacığı oluşturulmalıdır. İş parçacığı oluşturmanın maliyeti az değildir, bu nedenle programın performansını olumsuz etkiler ve hatta OOM hatasına bile yol açabilir. Bu nedenle, iş parçacıklarını yönetmek için bir iş parçacığı havuzu uygulamanız gerekir ve Java, ExecutorService sınıfını sunmaktadır.


public class MessageService {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void print(String message) {
        executorService.submit(() -> System.out.println(message));
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Toplam iş parçacığı sayısını 10'a sınırladık ve istediğimiz çoklu iş parçacığı yöntemindeki asenkron işlemeyi doğru bir şekilde yapabildik. Ancak, yukarıdaki yöntem, asenkron olarak işlenmesini istediğimiz her yöntem için ExecutorService'in submit() yöntemini uygulamayı gerektirir, bu da tekrarlayan değişiklik işleri gerektirir. Yani, başlangıçta senkron bir mantık olarak yazılmış bir yöntemi asenkron olarak değiştirmek istiyorsak, yöntemin kendisinin mantığında değişiklik yapmak kaçınılmazdır.


Spring @Async

Basit Yöntem

@EnableAsync
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

@Service
public class MessageService {

    @Async
    public void print(String message) {
        System.out.println(message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() {
        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


@EnableAsync ek açıklamasını Application sınıfının üzerine ekleyin ve asenkron olarak işlenmesini istediğiniz senkron mantık yönteminin üzerine @Async ek açıklamasını yapın, bu kadar. Ancak yukarıdaki yöntem, iş parçacıklarını yönetmediği sorununa sahiptir. Çünkü @Async'in varsayılan ayarı, SimpleAsyncTaskExecutor'ı kullanacak şekilde ayarlanmıştır ve bu, bir iş parçacığı havuzu değil, yalnızca iş parçacığı oluşturma işlevi görür.


Bir İş Parçacığı Havuzu Kullanma Yöntemi

Öncelikle Application sınıfındaki @EnableAsync'i kaldırın. Application sınıfında @EnableAutoConfiguration veya @SpringBootApplication yapılandırması varsa, çalışma zamanında @Configuration olarak yapılandırılmış SpringAsyncConfig sınıfının (aşağıda oluşturulacak) threadPoolTaskExecutor fasulye bilgilerini okuyacağı için.


@Configuration
@EnableAsync // Application'da değil, Async yapılandırma sınıfında eklenmelidir.
public class SpringAsyncConfig {

    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(3); // Temel iş parçacığı sayısı
        taskExecutor.setMaxPoolSize(30); // Maksimum iş parçacığı sayısı
        taskExecutor.setQueueCapacity(100); // Kuyruk boyutu
        taskExecutor.setThreadNamePrefix("Executor-");
        return taskExecutor;
    }


Çekirdek ve maksimum boyutları ayarlayabilirsiniz. Bu durumda, başlangıçta çekirdek boyutu kadar çalışacak ve işlem hızı düşerse, maksimum boyut kadar iş parçacığı artacağını tahmin edebilirsiniz, ancak bu doğru değil.


İçsel olarak, Integer.MAX_VALUE boyutunda bir LinkedBlockingQueue oluşturur ve çekirdek boyutu kadar iş parçacığı işlem yapamazsa, kuyrukta bekler. Kuyruk dolarsa, maksimum boyut kadar iş parçacığı oluşturarak işlem yapar.


Bu durumda, kuyruk boyutunu Integer.MAX_VALUE olarak ayarlamak zorsa, queueCapacity'yi ayarlayabilirsiniz. Yukarıdaki gibi yapılandırılırsa, başlangıçta 3 iş parçacığı tarafından işlem yapılır ve işlem hızı düşerse, işleri 100 boyutlu bir kuyruğa yerleştirir ve daha fazla istek gelirse, en fazla 30 iş parçacığı oluşturarak işleri işler.


İş parçacığı havuzu yapılandırması tamamlandıktan sonra, @Async ek açıklaması olan yöntemde yukarıdaki fasulye adını ekleyebilirsiniz.


@Service
public class MessageService {

    @Async("threadPoolTaskExecutor")
    public void print(String message) {
        System.out.println(message);
    }


Birkaç farklı iş parçacığı havuzu türünü yapılandırmak istiyorsanız, threadPoolTaskExecutor() gibi fasulye oluşturma yöntemlerini oluşturun ve @Async'i yapılandırırken istediğiniz iş parçacığı havuzu fasulyesini ekleyin.


Dönüş Tipine Göre Dönüş Biçimi

Dönüş değeri yoksa

Asenkron olarak işlenmesi gereken yöntemin işlem sonucunu iletmesi gerekmiyorsa, @Async ek açıklamasının dönüş tipini void olarak ayarlayabilirsiniz.


Dönüş değeri varsa

Future, ListenableFuture, CompletableFuture türlerini dönüş türü olarak kullanabilirsiniz. Asenkron yöntemin dönüş biçimini new AsyncResult() ile sarmalayabilirsiniz.


[Future]

@Service
public class MessageService {

    @Async
    public Future print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws ExecutionException, InterruptedException {
        for (int i = 1; i <= 5; i++) {
            Future future = messageService.print(i + "");
            System.out.println(future.get());
        }
    }
}

// Çalışma Sonuçları
Task Start - 1
jayon-1
Task Start - 2
jayon-2
Task Start - 3
jayon-3
Task Start - 4
jayon-4
Task Start - 5


future.get(), isteğin sonucu gelene kadar bekleme işlevi görür. Bu nedenle, asenkron engelleme yöntemi haline gelir ve performans iyi değildir. Genellikle Future kullanılmaz.


[ListenableFuture]

@Service
public class MessageService {

    @Async
    public ListenableFuture print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws InterruptedException {
        for (int i = 1; i <= 5; i++) {
            ListenableFuture listenableFuture = messageService.print(i + "");
            listenableFuture.addCallback(System.out::println, error -> System.out.println(error.getMessage()));
        }
    }
}

// Çalışma Sonuçları
Task Start - 1
Task Start - 3
Task Start - 2
jayon-1
jayon-2
Task Start - 5
jayon-3
Task Start - 4
jayon-4


ListenableFuture, geri çağrıları kullanarak engellemeyen bir şekilde işlem yapabilir. addCallback() yönteminin ilk parametresi işlem tamamlama geri çağrı yöntemidir, ikinci parametre ise işlem başarısızlık geri çağrı yöntemidir. İş parçacığı havuzunun çekirdek iş parçacıklarını 3 olarak ayarladığımız için, "Task Start" mesajının ilk olarak 3 adet yazıldığını görebilirsiniz.



[CompletableFuture]

ListenableFuture ile de engellemeyen mantık uygulayabiliriz, ancak geri çağrı içinde geri çağrıya ihtiyaç duyulursa, "geri çağrı cehennemi" olarak adlandırılan çok karmaşık bir kodu tetikler.


Untitled


Elbette bu sefer CompletableFuture'ı ayrıntılı olarak ele almayacağız, bu nedenle karmaşık geri çağrıları ele alan bir kod merak ediyorsanız, aşağıdaki kaynak bağlantısını inceleyebilirsiniz.


@Service
public class MessageService {

    @Async
    public CompletableFuture print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message).completable();
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws InterruptedException {
        for (int i = 1; i <= 5; i++) {
            CompletableFuture completableFuture = messageService.print(i + "");
            completableFuture
                    .thenAccept(System.out::println)
                    .exceptionally(error -> {
                        System.out.println(error.getMessage());
                        return null;
                    });
        }
    }


ListenableFuture'daki geri çağrı tanımından daha okunabilir ve engellemeyen işlevi mükemmel bir şekilde gerçekleştirir. Bu nedenle, @Async kullanırken, dönüş değerine ihtiyaç duyulursa, CompletableFuture kullanılması önerilir.


@Async'in Avantajları

Geliştiriciler, yöntemleri senkron olarak yazabilir ve asenkron bir yöntem isterlerse, sadece @Async ek açıklamasını yöntemin üzerine ekleyebilirler. Bu nedenle, senkron ve asenkron açısından iyi bir bakım kodu oluşturabilirsiniz.


@Async'in Dikkat Edilmesi Gereken Noktalar

@Async işlevini kullanmak için @EnableAsync ek açıklamasını bildirmeniz gerekir, ancak bu durumda ek bir yapılandırma yapılmazsa, vekil modunda çalışır. Yani, @Async ek açıklamasıyla çalışan asenkron yöntemler, tüm Spring AOP kısıtlamalarını olduğu gibi takip eder. Daha fazla bilgi içinBu yayın'a bakın.


  • Özel yöntemlerde @Async kullanılırsa bile, AOP çalışmaz.
  • Aynı nesne içindeki yöntemler birbirini çağırırsa, AOP çalışmaz.


Kaynaklar

제이온
제이온
제이온
제이온
[Java] Senkronize Edilmiş Koleksiyonlar vs Eşzamanlı Koleksiyonlar Java'da çoklu iş parçacıklı ortamlarda koleksiyonları kullanırken, eşzamanlılık sorunlarını çözmek için çeşitli yöntemleri ve avantajlarını ve dezavantajlarını karşılaştırdık. Vector, Hashtable, Collections.synchronizedXXX gibi senkronize edilmiş koleksiy

25 Nisan 2024

[Spring] Filter, Interceptor, Argument Resolver nedir? Spring web uygulamasında istekleri işleyen filtre, ara kesici ve Argüman Çözümleyicisinin kavramlarını ve aralarındaki farkları ayrıntılı olarak öğrenin. Her bir özelliğin nasıl uygulandığı, ne zaman kullanılacağı, avantajları ve dezavantajlarını karşılaş

27 Nisan 2024

[Efektif Java] Madde 6: Gereksiz Nesne Oluşturmayı Önleyin Java'da gereksiz nesne oluşturmayı azaltma yöntemleri hakkında bir kılavuz. String, Boolean gibi değişmez nesneler için literalleri kullanın ve düzenli ifadeler için Pattern örneklerini önbelleğe alın. Ayrıca, otomatik kutulama performans düşüşüne neden o

28 Nisan 2024

[Eşzamanlılık] Atomik İşlem: Bellek Çiti ve Bellek Sıralaması Bu blog yazısında, atomik işlemlerde bellek sıralamasının nasıl dikkate alınacağı ve Sıralama seçeneklerinin önemi açıklanmaktadır. Relaxed, Acquire, Release, AcqRel, SecCst gibi çeşitli Sıralama seçenekleri hakkında açıklamaların yanı sıra, her seçeneğin
곽경직
곽경직
곽경직
곽경직
곽경직

12 Nisan 2024

Rust'ın Eşzamanlılık Hatalarını Önleme Yolu Rust, eşzamanlı programlamanın zorluklarını aşmak için güçlü bir dildir. Tip sistemi ve sahiplik modeli sayesinde, iş parçacıkları arasında veri aktarımı ve paylaşımı güvenlidir. Mutex, Channel, Atomic gibi iç değişkenlik kalıpları ile paylaşılan değişken
곽경직
곽경직
곽경직
곽경직
곽경직

28 Mart 2024

[Bilişim alanında olmayanlar için, geliştirici olarak hayatta kalmak] 14. Yeni Başlayan Geliştiricilerin Sıkça Sorduğu Teknoloji Görüşme İçerikleri Özeti Yeni başlayan geliştiriciler için bir teknoloji görüşme hazırlık rehberidir. Ana bellek alanı, veri yapıları, RDBMS ve NoSQL, yordamsal ve nesne yönelimli, geçersiz kılma ve aşırı yükleme, sayfa değiştirme algoritmaları, süreçler ve iş parçacıkları, OSI 7
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 Nisan 2024

Şelale Geliştirme Yöntemi Nedir? Şelale geliştirme yöntemi, yazılım geliştirme sürecini gereksinim analizi, tasarım, uygulama, test, dağıtım ve bakım aşamalarına ayıran ve bunları sırayla uygulayan geleneksel bir yöntemdir. Bu yöntem, net yapısı ve dokümantasyonu avantajı sağlarken, gere
꿈많은청년들
꿈많은청년들
꿈많은청년들
꿈많은청년들
꿈많은청년들

14 Mayıs 2024

Supabase ve FCM Kullanarak Gerçek Zamanlı İtme Bildirimleri Sistemi Kurma Deno, Supabase ve Firebase Cloud Messaging (FCM) kullanarak gerçek zamanlı itme bildirimleri sistemi kurma yöntemini öğrenin. Veritabanı değişikliklerini algılama, itme bildirimleri gönderme gibi gerçek kod örnekleri ile ayrıntılı olarak açıklanmıştır.
Kofsitho
Kofsitho
Deno, Supabase ve Firebase Cloud Messaging kullanarak gerçek zamanlı itme
bildirimleri sistemi kurma
Kofsitho
Kofsitho

8 Şubat 2024

AI Tam Yığınını Açık Kaynaklarla Tamamlamak AI ekosisteminde yeni açık kaynaklı LLM (Büyük Dil Modeli) modelleri hızla ortaya çıkıyor. Mistral, Llama, phi-2 gibi güçlü performans ve açık lisanslara sahip modeller yayınlandı ve bunları kullanmak için çeşitli araçlar da geliştiriliyor. LangChain, Lla
RevFactory
RevFactory
RevFactory
RevFactory

5 Şubat 2024