1、簡介
在Java應用中,絕大多數狀況下都是經過同步的方式來實現交互處理的;可是在處理與第三方系統交互的時候,容易形成響應遲緩的狀況數據庫
2、解決辦法
辦法一:採用多線程實現異步操做多線程
新建一個線程類:app
public class MyThread extends Thread { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("。。。。。異步方法調用了。。。。。"); } }
在須要異步操做的地方,開啓異步線程:異步
@RequestMapping("/index") public String loginpage() { //開啓異步操做 Thread thread1=new Thread(new MyThread()); thread1.start(); return "login"; }
方法二:@Async註解
在Spring中,基於@Async標註的方法,稱之爲異步方法;這些方法將在執行的時候,將會在獨立的線程中被執行,調用者無需等待它的完成,便可繼續其餘的操做。
(1)基於Java配置的啓用方式:
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... } async
(2)基於XML配置文件的啓用方式
//加載bean
<bean id="asyncTest" class="com.utils.AsyncTest" lazy-init="false"/>
<task:executor id="myexecutor"pool-size="5"/>
<task:annotation-driven executor="myexecutor"/>ide
3、實際使用
(1)新建一個異步操做類測試
@Component public class AsyncTest { @Async("myexecutor") public void sayHello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("hello...hello"); } }
(2)在須要異步的地方,使用上述方法:spa
@Autowired private AsyncTest asyncTest; @RequestMapping("/index") public String loginpage() { System.out.println("開始調用 asyncTest.sayHello()"); asyncTest.sayHello(); System.out.println("結束調用 asyncTest.sayHello()"); return "login"; }
上述方法返回值是void的演示,還有存在返回值的異步操做;線程
改寫sayHello()方法 @Async("myexecutor") public Future<String> sayHello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("hello...hello"); return new AsyncResult<String>("這是sayHello()返回值"); }
打印sayHello()返回值 @RequestMapping("/index") public String loginpage() throws ExecutionException, InterruptedException { System.out.println("開始調用 asyncTest.sayHello()"); Future<String> results=asyncTest.sayHello(); System.out.println("結束調用 asyncTest.sayHello()"); while(true) { //這裏使用了循環判斷,等待獲取結果信息 if (results.isDone()) { //判斷是否執行完畢 System.out.println("Result from asynchronous process - " + results.get()); break; } } return "login"; }
獲取異步方法的結果信息,是經過不停的檢查Future的狀態來獲取當前的異步方法是否執行完畢來實現的
經實際測試發現,若是打印異步操做返回值,則是等待異步操做執行結束後才能得到返回值,如此一來整個流程下來花費時間和同步方法同樣。code
4、@Async調用中的事務處理機制
在@Async標註的方法,同時也適用了@Transactional進行了標註;在其調用數據庫操做之時,將沒法產生事務管理的控制,緣由就在於其是基於異步處理的操做。那該如何給這些操做添加事務管理呢?能夠將須要事務管理操做的方法放置到異步方法內部,在內部被調用的方法上添加@Transactional.
例如:
方法A,使用了@Async/@Transactional來標註,可是沒法產生事務控制的目的。 方法B,使用了@Async來標註, B中調用了C、D,C/D分別使用@Transactional作了標註,則可實現事務控制的目的。