Java เทียบเท่าของ C # async / รอ?


151

ฉันเป็นนักพัฒนา C # ปกติ แต่บางครั้งฉันก็พัฒนาแอปพลิเคชันใน Java ฉันสงสัยว่ามี Java เทียบเท่าของ C # async / รอ? ในคำง่าย ๆ เทียบเท่า java คืออะไร:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();
    var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
    return urlContents.Length;
}

7
ทำไมจึงเป็นเช่นนี้ดี: โทรกลับไปเป็นคำชี้แจงของคนรุ่นโดย Miguel de Icaza
andrewdotn

โซลูชันปัจจุบันของ Java คือการไม่จัดการกับค่าจริงนำหน้าด้วยasyncแต่ใช้FutureหรือObservableค่าแทน
SD

1
ไม่มีอะไรเทียบเท่า และมันก็เจ็บ อีกหนึ่งคุณลักษณะที่ขาดหายไปที่คุณต้องการในการแก้ไขปัญหาและไลบรารีที่ซับซ้อนโดยไม่ต้องใช้เอฟเฟกต์แบบเดียวกันกับคำสองคำนี้
สไปโร

เป็นที่น่าสังเกตว่าเป็นเวลานานที่นักออกแบบ Java ได้พยายามที่จะให้ Java bytecode ย้อนกลับเข้ากันได้กับการเปลี่ยนแปลงเพียงห้องสมุดและ Syntatic-Sugar รอบคุณสมบัติที่มีอยู่ ดูความจริงที่ว่ายาชื่อสามัญจะไม่เก็บข้อมูลชนิดเวลาทำงานและ lambders จะดำเนินการตามวัตถุที่ใช้อินเตอร์เฟซ async / คอยจะต้องมีการเปลี่ยนแปลงขนาดใหญ่มาก bytecode เป็นไปได้และดังนั้นฉันไม่คาดว่าจะเห็นมันใน java เร็ว ๆ นี้
Philip Couling

คำตอบ:


140

ไม่ไม่มีอะไรเทียบเท่า async / คอยใน Java - หรือแม้แต่ใน C # ก่อน v5

มันเป็นคุณสมบัติทางภาษาที่ค่อนข้างซับซ้อนในการสร้างเครื่องรัฐหลังฉาก

มีการสนับสนุนภาษาค่อนข้างน้อยสำหรับการซิงโครนัส / การทำงานพร้อมกันใน Java แต่java.util.concurrentแพ็คเกจมีคลาสที่มีประโยชน์มากมายรอบ ๆ สิ่งนี้ (ไม่เทียบเท่ากับ Task Parallel Library แต่ใกล้เคียงที่สุดกับมัน)


15
@ user960567: ไม่ประเด็นของฉันคือมันเป็นคุณสมบัติภาษา - ไม่สามารถใส่ในไลบรารีได้เท่านั้น ฉันไม่เชื่อว่ามีกำหนดการเทียบเท่าสำหรับ Java 8 อย่างน้อย
Jon Skeet

10
@ user960567: คุณต้องแยกความแตกต่างระหว่างเวอร์ชั่น C # ที่คุณกำลังใช้และเวอร์ชัน. NET ที่คุณใช้อยู่ async / await เป็นคุณลักษณะภาษา - มีการแนะนำใน C # 5 ใช่คุณสามารถใช้ Microsoft.Bcl.Async เพื่อใช้ async / รอการกำหนดเป้าหมาย. NET 4 แต่คุณยังต้องใช้คอมไพเลอร์ C # 5
Jon Skeet

5
@rozar: ไม่ไม่จริง มีหลายตัวเลือกสำหรับการซิงโครนัส - แต่ RxJava ไม่เปลี่ยนภาษาในวิธีที่ C # ทำ ฉันไม่มีอะไรเทียบกับ Rx ได้ แต่มันไม่เหมือนกับ async ใน C # 5
Jon Skeet

11
@DtechNet: มีเครื่องจักร JVM จำนวนมากซึ่งเป็นแบบอะซิงโครนัสใช่ ... ที่แตกต่างกันมากจากที่นั่นมีคุณสมบัติภาษาจริงที่สนับสนุนแบบอะซิงโครนัส (มีจำนวนมาก asynchrony เป็นใน .NET ก่อน async / รอคอยมากเกินไป ... แต่ async / ทำให้รอคอยมันไกลง่ายต่อการใช้ประโยชน์จากการที่.)
จอนสกีต

1
@Aarkon: ฉันจะโต้แย้งว่าถ้าไม่มีการสนับสนุนทางภาษาที่ชัดเจนคำตอบก็ยังคงถูกต้อง มันไม่ใช่แค่เรื่องของไลบรารีที่ทำให้การกำหนดเวลาง่ายขึ้น - วิธีที่คอมไพเลอร์ C # สร้างเครื่องรัฐมีความสำคัญที่นี่
Jon Skeet

41

awaitใช้ความต่อเนื่องในการดำเนินการรหัสเพิ่มเติมเมื่อเสร็จสิ้นการดำเนินการไม่ตรงกัน ( client.GetStringAsync(...))

ดังนั้นในฐานะที่ใกล้เคียงที่สุดฉันจะใช้โซลูชันCompletableFuture<T>(ตามมาตรฐาน Java 8 เทียบเท่ากับ. net Task<TResult>) เพื่อประมวลผลคำขอ Http แบบอะซิงโครนัส

อัปเดตเมื่อวันที่25-05-2559 เป็น AsyncHttpClient v.2 ที่เผยแพร่ใน Abril วันที่ 13 ของปี 2559:

ดังนั้น Java 8 ที่เทียบเท่ากับตัวอย่าง OP AccessTheWebAsync()คือ:

CompletableFuture<Integer> AccessTheWebAsync()
{
    AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
    return asyncHttpClient
       .prepareGet("http://msdn.microsoft.com")
       .execute()
       .toCompletableFuture()
       .thenApply(Response::getResponseBody)
       .thenApply(String::length);
}

การใช้งานนี้นำมาจากคำตอบของฉันจะได้รับ CompletableFuture จากคำขอไคลเอ็นต์ Async Http ได้อย่างไร และที่เป็นไปตาม API ใหม่ที่มีให้ในรุ่นที่ 2 ของAsyncHttpClientปล่อยออกมาในวันที่ 13 เมษายน 2016 CompletableFuture<T>ที่ได้รับการสนับสนุนที่แท้จริงแล้ว

คำตอบเดิมโดยใช้ AsyncHttpClient รุ่น 1:

ด้วยเหตุนี้เราจึงมีสองแนวทางที่เป็นไปได้:

  • คนแรกที่ใช้ non-blocking IO AccessTheWebAsyncNioและผมเรียกมันว่า แต่เนื่องจากAsyncCompletionHandlerเป็นคลาสนามธรรม (แทนที่จะเป็นส่วนต่อประสานการทำงาน) เราไม่สามารถผ่านแลมบ์ดาเป็นอาร์กิวเมนต์ได้ ดังนั้นมันจึงเกิดขึ้นอย่างหลีกเลี่ยงไม่ได้เนื่องจากไวยากรณ์ของคลาสที่ไม่ระบุชื่อ อย่างไรก็ตามวิธีนี้ใกล้เคียงกับขั้นตอนการดำเนินการของตัวอย่าง C # ที่ให้มามากที่สุด

  • ส่วนที่สองน้อยกว่า verbose เล็กน้อย แต่มันจะส่งงานใหม่ที่ท้ายที่สุดจะบล็อกเธรดf.get()จนกว่าการตอบสนองจะเสร็จสมบูรณ์

วิธีแรก , verbose เพิ่มเติม แต่ไม่ใช่การปิดกั้น:

static CompletableFuture<Integer> AccessTheWebAsyncNio(){
    final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
    final CompletableFuture<Integer> promise = new CompletableFuture<>();
    asyncHttpClient
        .prepareGet("https://msdn.microsoft.com")
        .execute(new AsyncCompletionHandler<Response>(){
            @Override
            public Response onCompleted(Response resp) throws Exception {
                promise.complete(resp.getResponseBody().length());
                return resp;
            }
        });
    return promise;
}

วิธีที่สอง verbose น้อยลง แต่บล็อกเธรด:

static CompletableFuture<Integer> AccessTheWebAsync(){
    try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){
        Future<Response> f = asyncHttpClient
            .prepareGet("https://msdn.microsoft.com")
            .execute();
        return CompletableFuture.supplyAsync(
            () -> return f.join().getResponseBody().length());
    }
}

1
ที่จริงแล้วนั่นเท่ากับการไหลของความสุข มันไม่ครอบคลุมการจัดการข้อยกเว้นในที่สุดและคนอื่น ๆ การรวมมันจะทำให้โค้ดมีความซับซ้อนและมีแนวโน้มที่จะเกิดข้อผิดพลาดได้ง่ายขึ้น
ฮาอิม

1
นี่ไม่ใช่ความต่อเนื่อง ตัวอย่างนี้พลาดจุดประสงค์ที่แท้จริงของ async / await ซึ่งจะปล่อยเธรดปัจจุบันเพื่อดำเนินการสิ่งอื่น ๆ และจากนั้นดำเนินการเรียกใช้เมธอดนี้บนเธรดปัจจุบันต่อไปหลังจากการตอบกลับมาถึง (สิ่งนี้อาจจำเป็นสำหรับเธรด UI ที่จะตอบสนองหรือเพื่อลดการใช้หน่วยความจำ) สิ่งที่ตัวอย่างนี้ทำคือการซิงโครไนซ์เธรดบล็อกแบบธรรมดารวมถึงการโทรกลับบางส่วน
Aleksandr Dubinsky

1
@AleksandrDubinsky ฉันเห็นด้วยกับคุณเมื่อคุณชี้ให้เห็นว่าการโทรกลับอาจไม่ทำงานบนเธรดผู้โทร คุณพูดถูก ฉันไม่เห็นด้วยเกี่ยวกับการบล็อกเธรด คำตอบที่อัปเดตของฉันสำหรับUPDATED เมื่อ 25-05-2016ไม่ใช่การปิดกั้น
Miguel Gamboa

1
.... และตัวอย่างนี้เป็นสาเหตุที่ทำให้ C # ง่ายต่อการเขียนและอ่านมากขึ้นเมื่อทำสิ่งที่ไม่ตรงกัน มันเป็นเพียงความเจ็บปวดใน Java
spyro

29

ลองใช้ea-asyncซึ่งเขียนโดย Java bytecode เพื่อจำลอง async / รอสวยอยู่ดี ตาม readme ของพวกเขา: "มันเป็นแรงบันดาลใจอย่างมากจาก Async-Await บน. NET CLR"


8
มีใครใช้ในการผลิตบ้างไหม?
Mr.Wang จาก Next Door

1
ดูเหมือนว่าอีเอจะทำฉันไม่คิดว่าพวกเขาจะใช้เงินกับสิ่งที่ไม่เหมาะสำหรับการผลิต
BrunoJCM

1
เป็นเรื่องปกติที่จะใช้เงินกับบางสิ่งและตัดสินใจว่ามันไม่เหมาะสำหรับการผลิต นั่นเป็นวิธีเดียวที่จะเรียนรู้ เป็นไปได้ที่จะใช้โดยไม่มีการตั้งค่าเอเจนต์ java ในการผลิต ที่ควรลดแถบเล็กน้อย ( github.com/electronicarts/ea-async )
thoredge

16

asyncและคอยเป็นน้ำตาลประโยค สาระสำคัญของ async และคอยเป็นเครื่องรัฐ คอมไพเลอร์จะแปลงรหัส async / คอยของคุณเป็นเครื่องรัฐ

ในเวลาเดียวกันเพื่อให้ async / รอการปฏิบัติจริงในโครงการจริงเราต้องมีฟังก์ชันไลบรารี Async I / Oจำนวนมากที่มีอยู่แล้ว สำหรับ C # ฟังก์ชัน I / O ที่ซิงโครไนซ์ดั้งเดิมส่วนใหญ่จะเป็นเวอร์ชั่น Async ทางเลือก เหตุผลที่เราต้องการฟังก์ชั่น Async เหล่านี้เป็นเพราะในกรณีส่วนใหญ่โค้ด async / await ของคุณจะต้มลงไปที่เมธอด Async ของไลบรารี

ฟังก์ชันไลบรารีเวอร์ชัน Async ใน C # เป็นแนวคิดแบบ AsynchronousChannel ใน Java ตัวอย่างเช่นเรามี AsynchronousFileChannel.read ซึ่งสามารถส่งคืน Future หรือรันการเรียกกลับหลังจากดำเนินการอ่าน แต่มันไม่เหมือนกันทุกประการ ฟังก์ชัน C # Async ทั้งหมดส่งคืนงาน (คล้ายกับอนาคต แต่มีประสิทธิภาพมากกว่าในอนาคต)

ดังนั้นสมมติว่า Java รองรับ async / คอยและเราเขียนโค้ดบางอย่างเช่นนี้:

public static async Future<Byte> readFirstByteAsync(String filePath) {
    Path path = Paths.get(filePath);
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    await channel.read(buffer, 0, buffer, this);
    return buffer.get(0);
}

จากนั้นฉันก็นึกภาพคอมไพเลอร์จะแปลง async / คอยรหัสต้นฉบับเป็นอะไรเช่นนี้:

public static Future<Byte> readFirstByteAsync(String filePath) {

    CompletableFuture<Byte> result = new CompletableFuture<Byte>();

    AsyncHandler ah = new AsyncHandler(result, filePath);

    ah.completed(null, null);

    return result;
}

และนี่คือการดำเนินการสำหรับ AsyncHandler:

class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
    CompletableFuture<Byte> future;
    int state;
    String filePath;

    public AsyncHandler(CompletableFuture<Byte> future, String filePath)
    {
        this.future = future;
        this.state = 0;
        this.filePath = filePath;
    }

    @Override
    public void completed(Integer arg0, ByteBuffer arg1) {
        try {
            if (state == 0) {
                state = 1;
                Path path = Paths.get(filePath);
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

                ByteBuffer buffer = ByteBuffer.allocate(100_000);
                channel.read(buffer, 0, buffer, this);
                return;
            } else {
                Byte ret = arg1.get(0);
                future.complete(ret);
            }

        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    @Override
    public void failed(Throwable arg0, ByteBuffer arg1) {
        future.completeExceptionally(arg0);
    }
}

15
น้ำตาล Syntatic คุณมีความคิดเกี่ยวกับวิธีการห่อข้อยกเว้นเกี่ยวกับรหัส async และวนรอบรหัส async หรือไม่?
Akash Kava

39
คลาสก็มีน้ำตาลเหมือนกัน คอมไพเลอร์สร้างทรีและรายการพอยน์เตอร์ของฟังก์ชั่นที่ปกติแล้วคุณจะเขียนด้วยมือให้คุณโดยอัตโนมัติ ฟังก์ชั่น / วิธีการเหล่านี้คือน้ำตาลซินแทคติคเช่นกัน พวกมันสร้าง gotos ทั้งหมดที่คุณปกติจะเป็นโปรแกรมเมอร์จริง ๆ เขียนด้วยมือ แอสเซมเบลอร์เป็นน้ำตาลซินแทคติคเช่นกัน โปรแกรมเมอร์จริงเขียนรหัสเครื่องและย้ายพอร์ตไปยังสถาปัตยกรรมเป้าหมายทั้งหมดด้วยตนเอง
Yeoman

32
เมื่อคิดว่าต่อไปคอมพิวเตอร์จะใช้น้ำตาลเชิงซ้อนสำหรับ l4m3 n00bz โปรแกรมเมอร์จริงประสานพวกเขาเข้ากับแผงวงจรเล็ก ๆ กับกระดานไม้และเชื่อมต่อพวกเขาด้วยลวดทองเพราะแผงวงจรนั้นเป็นน้ำตาลซินแทคติคเหมือนกับการผลิตจำนวนมากรองเท้าหรืออาหาร
Yeoman

14

ไม่มีเทียบเท่าของ C # async / รอใน Java ในระดับภาษา แนวคิดที่รู้จักกันในชื่อFibers aka กลุ่มการร่วมมือหรือ aka Thread Lightweightอาจเป็นทางเลือกที่น่าสนใจ คุณสามารถค้นหาไลบรารี Java ที่ให้การสนับสนุนเส้นใย

ไลบรารี Java ที่ใช้ Fibers

คุณสามารถอ่านบทความนี้ (จาก Quasar)สำหรับการแนะนำที่ดีกับเส้นใย ครอบคลุมสิ่งที่เป็นเธรดวิธีการนำไฟเบอร์ไปใช้งานบน JVM และมีโค้ดเฉพาะ Quasar


10
async / await ใน C # ไม่ใช่ไฟเบอร์ มันเป็นเพียงแค่คอมไพเลอร์เวทมนต์ที่ใช้ความต่อเนื่องใน Promise ( Taskคลาส) โดยการลงทะเบียนการโทรกลับ
UltimaWeapon

1
@UltimaWeapon คุณคิดว่าอะไรคือเส้นใย
Aleksandr Dubinsky

@AleksandrDubinsky ตัวอย่างหนึ่งคือ goroutine
UltimaWeapon

1
@UltimaWeapon ฉันกำลังมองหาคำอธิบาย
Aleksandr Dubinsky

@AleksandrDubinsky ฉันขี้เกียจอธิบาย หากคุณต้องการทราบอย่างแท้จริงคุณสามารถค้นหาบทความเกี่ยวกับภายใต้ประทุนของ goroutine
UltimaWeapon

8

ตามที่ได้กล่าวมาแล้วไม่มีความเทียบเท่าโดยตรง แต่สามารถสร้างการประมาณใกล้เคียงได้อย่างมากด้วยการดัดแปลง Java bytecode (สำหรับทั้งคำแนะนำแบบ async / ที่รอคอยและการใช้งานแบบต่อเนื่องเป็นต้น)

ฉันกำลังทำงานในโครงการที่ใช้ async / คอยบนไลบรารีต่อเนื่อง JavaFlowโปรดตรวจสอบhttps://github.com/vsilaev/java-async-await

ยังไม่มีการสร้าง Maven mojo แต่คุณสามารถรันตัวอย่างด้วยตัวแทน Java ที่ให้มา นี่คือลักษณะของรหัส async / await:

public class AsyncAwaitNioFileChannelDemo {

public static void main(final String[] argv) throws Exception {

    ...
    final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo();
    final CompletionStage<String> result = demo.processFile("./.project");
    System.out.println("Returned to caller " + LocalTime.now());
    ...
}


public @async CompletionStage<String> processFile(final String fileName) throws IOException {
    final Path path = Paths.get(new File(fileName).toURI());
    try (
            final AsyncFileChannel file = new AsyncFileChannel(
                path, Collections.singleton(StandardOpenOption.READ), null
            );              
            final FileLock lock = await(file.lockAll(true))
        ) {

        System.out.println("In process, shared lock: " + lock);
        final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size());

        await( file.read(buffer, 0L) );
        System.out.println("In process, bytes read: " + buffer);
        buffer.rewind();

        final String result = processBytes(buffer);

        return asyncResult(result);

    } catch (final IOException ex) {
        ex.printStackTrace(System.out);
        throw ex;
    }
}

@async เป็นคำอธิบายประกอบที่ตั้งค่าสถานะวิธีที่เรียกใช้งานแบบอะซิงโครนัสรอ () เป็นฟังก์ชันที่รอให้ CompletableFuture ใช้การดำเนินการต่อเนื่องและการเรียกเพื่อ "return asyncResult (someValue)" เป็นสิ่งที่เกี่ยวข้อง

เช่นเดียวกับ C #, การควบคุมการไหลถูกเก็บรักษาไว้และการจัดการข้อยกเว้นอาจทำได้ในลักษณะปกติ (ลอง / จับเช่นในรหัสที่ดำเนินการตามลำดับ)


6

Java ตัวมันเองไม่มีคุณสมบัติเทียบเท่า แต่ห้องสมุดของบุคคลที่สามที่มีอยู่ซึ่งมีฟังก์ชันการทำงานที่คล้ายกันเช่นKilim


3
ฉันไม่คิดว่าห้องสมุดนี้มีส่วนเกี่ยวข้องกับสิ่งที่ async / waitit ทำ
ธาน

5

ก่อนอื่นให้ทำความเข้าใจว่า async / คอยคืออะไร มันเป็นวิธีสำหรับแอปพลิเคชัน GUI แบบเธรดเดียวหรือเซิร์ฟเวอร์ที่มีประสิทธิภาพในการรันหลาย ๆ "เส้นใย" หรือ "ร่วมกิจวัตร" หรือ "กระทู้เบา" ในหัวข้อเดียว

หากคุณมีความตกลงกับใช้หัวข้อสามัญแล้วเทียบเท่า Java เป็นและExecutorService.submit Future.getสิ่งนี้จะบล็อกจนกว่างานจะเสร็จสมบูรณ์และส่งคืนผลลัพธ์ ในขณะเดียวกันเธรดอื่นสามารถทำงานได้

หากคุณต้องการประโยชน์ของสิ่งต่าง ๆ เช่นไฟเบอร์คุณต้องการการสนับสนุนในคอนเทนเนอร์ (ฉันหมายถึงในเหตุการณ์ GUI หรือในเซิร์ฟเวอร์ตัวจัดการการร้องขอ HTTP) หรือโดยการเขียนของคุณเอง

ตัวอย่างเช่น Servlet 3.0 เสนอการประมวลผลแบบอะซิงโครนัส javafx.concurrent.Taskข้อเสนอ JavaFX สิ่งเหล่านี้ไม่มีคุณสมบัติด้านภาษาที่หรูหรา พวกเขาทำงานผ่านการเรียกกลับสามัญ


2
นี่คือบทความที่อ้างถึงการเริ่มย่อหน้าแรกของคำตอบนี้ // เริ่มต้นคำพูดสำหรับแอปพลิเคชันไคลเอนต์เช่น Windows Store, เดสก์ท็อป Windows และแอพ Windows Phone ประโยชน์หลักของ async คือการตอบสนอง แอพประเภทนี้ใช้ async เป็นหลักในการตอบสนองต่อ UI สำหรับแอปพลิเคชันเซิร์ฟเวอร์ประโยชน์หลักของ async คือความยืดหยุ่น msdn.microsoft.com/en-us/magazine/dn802603.aspx
granadaCoder

3

มีอะไรที่ไม่พื้นเมือง Java ที่ช่วยให้คุณทำเช่นนี้ async / รอคอยคำหลัก แต่สิ่งที่คุณสามารถทำได้ถ้าคุณอยากจะมีที่ใช้CountDownLatch จากนั้นคุณสามารถเลียนแบบ async / รอโดยผ่านสิ่งนี้ (อย่างน้อยใน Java7) นี่เป็นวิธีปฏิบัติทั่วไปในการทดสอบหน่วย Android ที่เราต้องทำการโทรแบบ async (โดยปกติแล้วจะเรียกใช้งานได้โดยตัวจัดการ) แล้วรอผล (นับถอยหลัง)

การใช้สิ่งนี้อย่างไรก็ตามในใบสมัครของคุณซึ่งตรงข้ามกับการทดสอบของคุณไม่ใช่สิ่งที่ฉันแนะนำ นั่นจะเป็นสิ่งที่น่ารังเกียจอย่างยิ่งเมื่อ CountDownLatch ขึ้นอยู่กับคุณอย่างมีประสิทธิภาพในการนับจำนวนครั้งและในสถานที่ที่เหมาะสม


3

ฉันสร้างและเผยแพร่ Java async / คอยไลบรารี https://github.com/stofu1234/kamaitachi

ไลบรารีนี้ไม่ต้องการนามสกุลคอมไพเลอร์และตระหนักถึงการประมวลผล IO แบบไม่ซ้อนใน Java

    async Task<int> AccessTheWebAsync(){ 
        HttpClient client= new HttpClient();
        var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
       return urlContents.Length;
    }

   ↓

    //LikeWebApplicationTester.java
    BlockingQueue<Integer> AccessTheWebAsync() {
       HttpClient client = new HttpClient();
       return awaiter.await(
            () -> client.GetStringAsync("http://msdn.microsoft.com"),
            urlContents -> {
                return urlContents.length();
            });
    }
    public void doget(){
        BlockingQueue<Integer> lengthQueue=AccessTheWebAsync();
        awaiter.awaitVoid(()->lengthQueue.take(),
            length->{
                System.out.println("Length:"+length);
            }
            );
    }

1

Java มีโชคไม่เทียบเท่า async / await สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับคือ ListenableFuture จาก Guava และ Listener chaining แต่มันก็ยังเป็นเรื่องยุ่งยากมากที่จะเขียนสำหรับกรณีที่เกี่ยวข้องกับการเรียกแบบอะซิงโครนัสหลายครั้งเนื่องจากระดับการซ้อนจะเติบโตอย่างรวดเร็ว

หากคุณตกลงกับการใช้ภาษาอื่นที่อยู่ด้านบนของ JVM โชคดีที่มี async / await ใน Scala ซึ่งเป็น C # async โดยตรง / รอคอยเทียบเท่ากับไวยากรณ์และความหมายที่เหมือนกันเกือบ: https://github.com/scala/ async /

โปรดทราบว่าแม้ว่าฟังก์ชันนี้ต้องการการสนับสนุนคอมไพเลอร์ขั้นสูงใน C # แต่ใน Scala สามารถเพิ่มเป็นห้องสมุดได้ด้วยระบบแมโครที่ทรงพลังมากใน Scala และสามารถเพิ่มได้แม้กระทั่ง Scala รุ่นเก่าเช่น 2.10 นอกจากนี้ Scala ยังเข้ากันได้กับ Java ดังนั้นคุณสามารถเขียนรหัส async ใน Scala แล้วเรียกมันจาก Java

นอกจากนี้ยังมีอีกโครงการที่คล้ายกันที่เรียกว่า Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.htmlซึ่งใช้ถ้อยคำต่างกัน แต่แนวคิดจะคล้ายกันมาก แต่นำมาใช้โดยใช้ตัวคั่นแบบต่อเนื่องไม่ใช่แมโคร (ดังนั้นจึงใช้งานได้กับ Scala เวอร์ชันที่เก่ากว่าเช่น 2.9)


1

Java ไม่มีคุณสมบัติเทียบเท่าโดยตรงกับภาษา C # ที่เรียกว่า async / await แต่มีวิธีการที่แตกต่างจากปัญหาที่ async / คอยพยายามแก้ไข เรียกว่าโปรเจ็กต์Loomซึ่งจะให้เธรดเสมือนจริงสำหรับการทำงานพร้อมกันของปริมาณงานสูง จะสามารถใช้ได้ใน OpenJDK บางรุ่นในอนาคต

วิธีการนี้ยังแก้ไข " ปัญหาฟังก์ชันสี " ที่ async / await มี

คุณสมบัติที่คล้ายกันสามารถพบได้ใน Golang ( goroutines )


0

หากคุณเพิ่งทำความสะอาดโค้ดซึ่งจำลองเอฟเฟกต์เดียวกันกับ async / คอยในจาวาและไม่รังเกียจที่จะปิดกั้นเธรดที่ถูกเรียกใช้จนกว่าจะเสร็จสิ้นเช่นในการทดสอบคุณสามารถใช้บางอย่างเช่นรหัสนี้:

interface Async {
    void run(Runnable handler);
}

static void await(Async async) throws InterruptedException {

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    async.run(new Runnable() {

        @Override
        public void run() {
            countDownLatch.countDown();
        }
    });
    countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS);
}

    await(new Async() {
        @Override
        public void run(final Runnable handler) {
            yourAsyncMethod(new CompletionHandler() {

                @Override
                public void completion() {
                    handler.run();
                }
            });
        }
    });

0

ไลบรารี AsynHelper Java ประกอบด้วยชุดของคลาส / วิธีการยูทิลิตี้สำหรับการโทรแบบอะซิงโครนัส (และรอ)

หากต้องการเรียกใช้ชุดการเรียกเมธอดหรือบล็อคโค้ดแบบอะซิงโครนัสกระบวนการจะรวมเมธอดตัวช่วยเหลือที่มีประโยชน์AsyncTask .submitTasksตามด้านล่างตัวอย่าง

AsyncTask.submitTasks(
    () -> getMethodParam1(arg1, arg2),
    () -> getMethodParam2(arg2, arg3)
    () -> getMethodParam3(arg3, arg4),
    () -> {
             //Some other code to run asynchronously
          }
    );

หากต้องการรอจนกว่ารหัสอะซิงโครนัสทั้งหมดจะทำงานเสร็จสมบูรณ์AsyncTask.submitTasksAndWait varient สามารถใช้งานได้

นอกจากนี้หากต้องการรับค่าส่งคืนจากการเรียกใช้เมธอดแบบอะซิงโครนัสหรือการบล็อกรหัสแต่ละครั้งสามารถใช้AsyncSupplier .submitSuppliersเพื่อให้ได้ผลลัพธ์จากอาร์เรย์ผู้จัดหาผลลัพธ์ที่ส่งคืนโดยวิธีการ ด้านล่างนี้เป็นตัวอย่างข้อมูล:

Supplier<Object>[] resultSuppliers = 
   AsyncSupplier.submitSuppliers(
     () -> getMethodParam1(arg1, arg2),
     () -> getMethodParam2(arg3, arg4),
     () -> getMethodParam3(arg5, arg6)
   );

Object a = resultSuppliers[0].get();
Object b = resultSuppliers[1].get();
Object c = resultSuppliers[2].get();

myBigMethod(a,b,c);

หากประเภทการคืนของแต่ละวิธีแตกต่างกันให้ใช้ตัวอย่างข้อมูลด้านล่าง

Supplier<String> aResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam1(arg1, arg2));
Supplier<Integer> bResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam2(arg3, arg4));
Supplier<Object> cResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam3(arg5, arg6));

myBigMethod(aResultSupplier.get(), bResultSupplier.get(), cResultSupplier.get());

ผลลัพธ์ของการเรียกใช้วิธีการแบบอะซิงโครนัส / การบล็อกรหัสสามารถรับได้ที่จุดต่าง ๆ ของรหัสในเธรดเดียวกันหรือเธรดที่แตกต่างกันในข้อมูลตัวอย่างด้านล่าง

AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam1(arg1, arg2), "a");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam2(arg3, arg4), "b");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam3(arg5, arg6), "c");


//Following can be in the same thread or a different thread
Optional<String> aResult = AsyncSupplier.waitAndGetFromSupplier(String.class, "a");
Optional<Integer> bResult = AsyncSupplier.waitAndGetFromSupplier(Integer.class, "b");
Optional<Object> cResult = AsyncSupplier.waitAndGetFromSupplier(Object.class, "c");

 myBigMethod(aResult.get(),bResult.get(),cResult.get());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.