spring boot非同步方法@Async踩坑

郝澤龍_HZ發表於2021-11-21

前言

我的需求是建立一個新執行緒來執行一些操作,因為如果用同一個執行緒就會導致資源一直被佔據,影響響應效率。

非同步的概念

我的理解:非同步即為在多輛車在多條路上行駛,同步即為多輛車在一條路上行駛。舉個例子:同步:當前如果正在學習c語言的話,那麼我們按照課程安排是不應該學習c++的,只有等這個學期結束學完c語言,下個學期才能學習c++。非同步:離散數學和c語言都是在本學期學習,你不必等c語言學完再學離散數學。

spring boot如何實現非同步

Google搜尋發現存在非同步的註解。
image.png

How To Do @Async in Spring

image.png
image.png
image.png
image.png

@Async
public void asyncMethodWithVoidReturnType() {
    System.out.println("Execute method asynchronously. " 
      + Thread.currentThread().getName());
}

總結:1.開啟非同步支援 2.非同步註解使用注意 3.非同步示例

我的非同步踩坑

1.未仔細閱讀two limitations:Self-invocation — won't work.

測試程式碼如下:

public class AsyncTest {
  @Test
  public void test1() {
    System.out.println("test1的執行緒id為:" + Thread.currentThread().getId());
    test2();
  }
  
  @Async
  public void test2() {
    System.out.println("test2的執行緒id為:" + Thread.currentThread().getId());
  }
}

效果:兩個都是同一個執行緒,並沒有達到test2是獨立的執行緒的效果
image.png
解決方案:將test2放到另一個class中,自我呼叫將不會生效。

2.必須為@Component或@Service註解才能使@Async生效

在將非同步方法放到其他類:

// 第一個類
public class AsyncTest1 {
  public void test1() {
    System.out.println("test1的執行緒id為:" + Thread.currentThread().getId());
    // 新建一個AsyncTest2類,呼叫其非同步方法
    AsyncTest2 asyncTest2 = new AsyncTest2();
    asyncTest2.test2();
  }
}

// 第二個類,定義非同步方法
public class AsyncTest2 {
  @Async
  public void test2() {
    System.out.println("test2的執行緒id為:" + 
        Thread.currentThread().getId());
  }
}

But:結果不隨我願,依然是列印顯示是同一執行緒。

解決:

Spring creates a proxy for each service and component you create using the common annotations. Only those proxies contain the wanted behavior defined by the method annotations such as the Async. So, calling those method not via the proxy but by the original naked class would not trigger those behaviors.
簡言之:spring將會給用@Component和@Service的類創造代理,只有擁有代理的類才能在使用@Async時得到想要的結果。

相關文章