java如何實現異步(通過子線程)


1. jdk1.8之前的Future

jdk並發包里的Future代表了未來的某個結果,當我們向線程池中提交任務的時候會返回該對象,可以通過future獲得執行的結果,但是jdk1.8之前的Future有點雞肋,並不能實現真正的異步,需要阻塞的獲取結果,或者不斷的輪詢。

通常我們希望當線程執行完一些耗時的任務后,能夠自動的通知我們結果,很遺憾這在原生jdk1.8之前是不支持的,但是我們可以通過第三方的庫實現真正的異步回調。

/**
* jdk1.8之前的Future
* @author Administrator
*/
public class JavaFuture {
public static void main(String[] args) throws Throwable, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> f = executor.submit(new Callable<String>() {

@Override
public String call() throws Exception {
System.out.println("task started!");
longTimeMethod();
System.out.println("task finished!");
return "hello";
}
});

//此處get()方法阻塞main線程
System.out.println(f.get());//這里需要等待執行結果
System.out.println("main thread is blocked");
}
}

如果想獲得耗時操作的結果,可以通過get()方法獲取,但是該方法會阻塞當前線程,我們可以在做完剩下的某些工作的時候調用get()方法試圖去獲取結果。

也可以調用非阻塞的方法isDone來確定操作是否完成,isDone這種方式有點兒類似下面的過程:(同步非阻塞)

image-20211124171202689

 

2. jdk1.8開始的Future

直到jdk1.8才算真正支持了異步操作,jdk1.8中提供了lambda表達式,使得java向函數式語言又靠近了一步。借助jdk原生的CompletableFuture可以實現異步的操作,同時結合lambada表達式大大簡化了代碼量。代碼例子如下:

簡單異步實現

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

public class JavaPromise {
   public static void main(String[] args) throws Throwable, ExecutionException {
       // 兩個線程的線程池
       ExecutorService executor = Executors.newFixedThreadPool(2);
       //jdk1.8之前的實現方式
       CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
           @Override
           public String get() {
               System.out.println("task started!");
               try {
                   //模擬耗時操作
                   Thread.sleep(5000);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
               return "task finished!";
          }
      }, executor);//這里會直接運行這個代碼

       //采用lambada的實現方式
       future.thenAccept(e -> System.out.println(e + " ok"));

       System.out.println("main thread is running");
  }

}

執行結果:
task started!
main thread is running
task finished! ok




3. Java如何將異步調用轉為同步

換句話說,就是需要在異步調用過程中,持續阻塞至獲得調用結果。

    • 使用wait和notify方法

    • 使用條件鎖

    • Future

    • 使用CountDownLatch

    • 使用CyclicBarrier


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM