जावा में एसिंक्रोनसली तरीके से कॉल कैसे करें


126

मैं हाल ही में गो के गोरोइन को देख रहा हूं और सोचा है कि जावा में भी ऐसा ही होना अच्छा होगा। जहाँ तक मैंने एक विधि कॉल को समानांतर करने का सामान्य तरीका खोजा है वह कुछ ऐसा करना है:

final String x = "somethingelse";
new Thread(new Runnable() {
           public void run() {
                x.matches("something");             
    }
}).start();

बहुत सुरुचिपूर्ण नहीं है। क्या ऐसा करने का कोई बेहतर तरीका है? मुझे एक परियोजना में इस तरह के समाधान की आवश्यकता थी इसलिए मैंने एक async विधि कॉल के आसपास अपने स्वयं के रैपर वर्ग को लागू करने का निर्णय लिया।

मैंने जे-गो में अपना रैपर क्लास प्रकाशित किया । लेकिन मुझे नहीं पता कि यह एक अच्छा समाधान है या नहीं। उपयोग सरल है:

SampleClass obj = ...
FutureResult<Integer> res = ...
Go go = new Go(obj);
go.callLater(res, "intReturningMethod", 10);         //10 is a Integer method parameter
//... Do something else
//...
System.out.println("Result: "+res.get());           //Blocks until intReturningMethod returns

या कम क्रिया:

Go.with(obj).callLater("myRandomMethod");
//... Go away
if (Go.lastResult().isReady())                //Blocks until myRandomMethod has ended
    System.out.println("Method is finished!");

आंतरिक रूप से मैं एक वर्ग का उपयोग कर रहा हूं जो कि रननेबल को लागू करता है और सही विधि ऑब्जेक्ट प्राप्त करने और इसे लागू करने के लिए कुछ परावर्तन कार्य करता है।

मैं अपने छोटे पुस्तकालय के बारे में कुछ राय चाहता हूं और इस तरह से जावा में इस तरह से एस्क्लेप मेथड कॉल करता हूं। क्या ये सुरक्षित है? वहाँ पहले से ही एक सरल तरीका है?


1
क्या आप जे-गो के अपने कोड को दोबारा दिखा सकते हैं?
19

मैं एक प्रोजेक्ट पर काम कर रहा था, जहां मैं एक स्ट्रीम चार वार पढ़ रहा था। एक बार एक पूरा शब्द पढ़ने के बाद मैं उस शब्द पर कई ऑपरेशन कर रहा था। अंत में मैंने इसे एक संग्रह में रखा। एक बार स्ट्रीम से सभी डेटा पढ़ने के बाद, मैं प्रतिक्रिया वापस करता हूं। मैंने हर बार एक शब्द पर ऑपरेशन करने के लिए धागा शुरू करने का फैसला किया। लेकिन इसने समग्र प्रदर्शन को कम कर दिया। तब मुझे पता चला कि धागे अपने आप में एक महंगे ऑपरेशन हैं। मुझे यकीन नहीं है कि किसी सूत्र को कॉल करने के लिए एक सूत्र शुरू करने से कोई भी प्रदर्शन जोड़ सकता है जब तक कि वह किसी भी भारी आईओ ऑपरेशन का प्रदर्शन नहीं कर रहा है।
अमित कुमार गुप्ता 12

2
बड़ा सवाल !! जावा 8 इसके लिए कंप्लीटटेबलफ्यूचर प्रदान करता है। अन्य उत्तर जावा के पुराने संस्करणों पर आधारित हैं
प्रोग्रामर

जवाबों:


155

मुझे अभी पता चला है कि आपके करने के लिए एक क्लीनर तरीका है

new Thread(new Runnable() {
    public void run() {
        //Do whatever
    }
}).start();

(कम से कम जावा 8 में), आप इसे छोटा करने के लिए एक लैम्ब्डा अभिव्यक्ति का उपयोग कर सकते हैं:

new Thread(() -> {
    //Do whatever
}).start();

जेएस में एक समारोह बनाने के रूप में सरल!


आपके उत्तर ने मेरी समस्या - stackoverflow.com/questions/27009448/… में मदद की । मेरी सीटेटोइन को लागू करने के लिए थोड़ा मुश्किल है, लेकिन अंततः यह काम किया :)
डेकवर्ड

मापदंडों के साथ कैसे कॉल करें?
यतनदाम

2
@yatanadam यह आपके प्रश्न का उत्तर दे सकता है। बस उपरोक्त कोड को एक विधि के अंदर रखें और वैरिएबल को वैसा ही पेस करें जैसा आप सामान्य रूप से करते हैं। इस परीक्षण कोड को देखें जो मैंने आपके लिए बनाया था।
user3004449

1
@eNnillaMS चलाने के बाद क्या धागा बंद करना पड़ता है? क्या यह स्वचालित रूप से बंद हो जाता है, या कचरा कलेक्टर द्वारा ?
user3004449

@ user3004449 थ्रेड स्वचालित रूप से बंद हो जाता है, हालाँकि, आप इसे भी बाध्य कर सकते हैं।
शॉन

58

जावा 8 ने पैकेज java.util.concurrent.CompletableFuture में उपलब्ध कम्पोज़िटेबल फ़ॉइल को पेश किया, एक एसिंच कॉल करने के लिए इस्तेमाल किया जा सकता है:

CompletableFuture.runAsync(() -> {
    // method call or code to be asynch.
});

CompletableFutureएक अन्य उत्तर में उल्लेख किया गया था, लेकिन उस एक ने पूरी supplyAsync(...)श्रृंखला का उपयोग किया । यह एक साधारण आवरण है जो प्रश्न को पूरी तरह से फिट करता है।
ndm13

ForkJoinPool.commonPool().execute()ओवरहेड थोड़ा कम है
मार्क जेरोनिमस

31

आप कक्षा पर भी विचार कर सकते हैं java.util.concurrent.FutureTask

यदि आप जावा 5 या उसके बाद का उपयोग कर रहे हैं, तो FutureTask "ए कैंसिलेबल एसिंक्रोनस कंप्यूटेशन" का टर्नकी कार्यान्वयन है।

java.util.concurrentपैकेज में उपलब्ध समृद्ध अतुल्यकालिक निष्पादन शेड्यूलिंग व्यवहार (उदाहरण के लिए ScheduledExecutorService) भी हैं, लेकिन FutureTaskआपके लिए आवश्यक सभी कार्यक्षमता हो सकती है।

मैं यहां तक ​​कहूंगा कि यह अब उपलब्ध नहीं है कि पहले उदाहरण के रूप में दिए गए पहले कोड पैटर्न का उपयोग करना उचित नहीं है क्योंकि FutureTaskयह उपलब्ध हो गया है। (मान लें कि आप जावा 5 या उसके बाद के हैं)


बात यह है कि मैं सिर्फ एक विधि कॉल को निष्पादित करना चाहता हूं। इस तरह मुझे लक्ष्य वर्ग के कार्यान्वयन को बदलना होगा। बात मैं चाहता था वास्तव में Runnable या प्रतिदेय को लागू करने के बारे में चिंता किए बिना कॉल है
फेलिप हम्मेल

मैं तुम्हें सुनता हूं। जावा में (अभी तक) प्रथम श्रेणी के कार्य नहीं हैं, इसलिए यह अभी कला की स्थिति है।
शादित

'भविष्य' कीवर्ड के लिए धन्यवाद ... अब मैं उनके बारे में ट्यूटोरियल खोल रहा हूं ... बहुत उपयोगी। : डी
गमरुह

4
-1 जहाँ तक मैं बता सकता हूँ, FutureTask अपने आप में कुछ भी अतुल्यकालिक रूप से चलाने के लिए पर्याप्त नहीं है। कार्लोस के उदाहरण के अनुसार, इसे चलाने के लिए आपको थ्रेड या एक्जिक्यूटर बनाने की आवश्यकता है।
मिकफहले

24

मुझे उस के लिए प्रतिबिंब का उपयोग करने का विचार पसंद नहीं है।
न केवल कुछ रिफैक्टिंग में इसे गायब करने के लिए खतरनाक है, बल्कि इससे इनकार भी किया जा सकता है SecurityManager

FutureTaskjava.util.concurrent पैकेज से अन्य विकल्पों के रूप में एक अच्छा विकल्प है।
साधारण कार्यों के लिए मेरा पसंदीदा:

    Executors.newSingleThreadExecutor().submit(task);

थोड़ा एक थ्रेड (काम के लिए एक प्रतिदेय या एक Runnable है) बनाने की तुलना में कम बिट


1
बात यह है कि मैं सिर्फ एक विधि कॉल को निष्पादित करना चाहता हूं। इस तरह मुझे लक्ष्य वर्ग के कार्यान्वयन को बदलना होगा। बात मैं चाहता था वास्तव में Runnable या प्रतिदेय को लागू करने के बारे में चिंता किए बिना कॉल है
फेलिप हम्मेल

तो यह बहुत मदद नहीं करेगा :( लेकिन आम तौर पर मैं प्रतिबिंब के बजाय एक Runnable या Callable का उपयोग करना पसंद करूंगा
user85421

4
बस एक छोटी टिप्पणी: यह ExecutorServiceउदाहरण का ट्रैक रखने के लिए अच्छा है , इसलिए आप shutdown()जब चाहें कॉल कर सकते हैं ।
डैनियल सजेले

1
यदि आपने ऐसा किया है, तो क्या आप संभवतः अन-बंद ExecutorService के साथ समाप्त नहीं होंगे, जिससे आपका JVM शटडाउन से इनकार कर सकता है? मैं एक सिंगल-थ्रेडेड, टाइम-लिमिटेड, एक्सेकॉर्स सर्विस पाने के लिए अपना खुद का तरीका लिखने की सलाह दूंगा।
djangofan

14

कंप्लीटटेबल सिवनी के लिए आप Java8 सिंटैक्स का उपयोग कर सकते हैं, इस तरह आप एस्कॉन फ़ंक्शन को कॉल करने के परिणामस्वरूप परिणाम के आधार पर अतिरिक्त async संगणना कर सकते हैं।

उदाहरण के लिए:

 CompletableFuture.supplyAsync(this::findSomeData)
                     .thenApply(this:: intReturningMethod)
                     .thenAccept(this::notify);

अधिक जानकारी इस लेख में मिल सकती है


10

आप jcabi-पहलुओं और AspectJ @Asyncसे एनोटेशन का उपयोग कर सकते हैं :

public class Foo {
  @Async
  public void save() {
    // to be executed in the background
  }
}

जब आप कॉल करते हैं save(), तो एक नया धागा शुरू होता है और इसके शरीर को निष्पादित करता है। के परिणाम की प्रतीक्षा किए बिना आपका मुख्य सूत्र जारी है save()


1
ध्यान दें कि यह दृष्टिकोण अतुल्यकालिक को बचाने के लिए सभी कॉल करेगा, जो हम चाहते हैं या नहीं हो सकता है। ऐसे मामलों में जब किसी दिए गए तरीके से केवल कुछ कॉल को एसिंक्स बनाया जाना चाहिए, इस पृष्ठ पर सुझाए गए अन्य तरीकों का उपयोग किया जा सकता है।
बेमोरिन

क्या मैं इसे वेब एप्लिकेशन में उपयोग कर सकता हूं (चूंकि थ्रेड्स को प्रबंधित करने की अनुशंसा नहीं की गई है)?
onlinenaman

8

आप इसके लिए Future-AsyncResult का उपयोग कर सकते हैं।

@Async
public Future<Page> findPage(String page) throws InterruptedException {
    System.out.println("Looking up " + page);
    Page results = restTemplate.getForObject("http://graph.facebook.com/" + page, Page.class);
    Thread.sleep(1000L);
    return new AsyncResult<Page>(results);
}

संदर्भ: https://spring.io/guides/gs/async-method/


10
यदि आप स्प्रिंग-बूट का उपयोग कर रहे हैं।
जियोवानी टॉराल्डो

6

जावा भी async विधियों को कॉल करने का एक अच्छा तरीका प्रदान करता है। में java.util.concurrent हमारे पास ExecutorService है कि एक ही करने में मदद करता है। अपनी वस्तु को इस तरह शुरू करें -

 private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

और फिर फ़ंक्शन को कॉल करें जैसे-

asyncExecutor.execute(() -> {

                        TimeUnit.SECONDS.sleep(3L);}

3

यह शायद एक वास्तविक समाधान नहीं है, लेकिन अब - जावा 8 में - आप लैम्ब्डा अभिव्यक्ति का उपयोग करके इस कोड को कम से कम थोड़ा बेहतर बना सकते हैं।

final String x = "somethingelse";
new Thread(() -> {
        x.matches("something");             
    }
).start();

और आप इसे एक पंक्ति में भी कर सकते हैं, फिर भी यह बहुत पठनीय है।

new Thread(() -> x.matches("something")).start();

जावा 8.
मुक्ति

3

आप कैक्टसAsyncFunc से उपयोग कर सकते हैं :

boolean matches = new AsyncFunc(
  x -> x.matches("something")
).apply("The text").get();

इसे पृष्ठभूमि पर निष्पादित किया जाएगा और परिणाम get()ए के रूप में उपलब्ध होगा Future


2

यह वास्तव में संबंधित नहीं है, लेकिन अगर मैं अतुल्यकालिक रूप से एक विधि को कॉल करता हूं जैसे मैच (), तो मैं उपयोग करूंगा:

private final static ExecutorService service = Executors.newFixedThreadPool(10);
public static Future<Boolean> matches(final String x, final String y) {
    return service.submit(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return x.matches(y);
        }

    });
}

फिर अतुल्यकालिक विधि का उपयोग करने के लिए मैं उपयोग करूंगा:

String x = "somethingelse";
try {
    System.out.println("Matches: "+matches(x, "something").get());
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

मैंने इसका परीक्षण किया है और यह काम करता है। अगर यह सिर्फ "अतुल्यकालिक विधि" के लिए आया था तो बस दूसरों की मदद कर सकता है।


1

ईएस द्वारा बनाई गई Async-Await के लिए अच्छी लाइब्रेरी भी है: https://github.com/electronicarts/ea-async

उनके Readme से:

ईए Async के साथ

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }
}

ईए Async के बिना

import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        return bank.decrement(cost)
            .thenCompose(result -> {
                if(!result) {
                    return completedFuture(false);
                }
                return inventory.giveItem(itemTypeId).thenApply(res -> true);
            });
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.