JavaRush /جاوا بلاگ /Random-SD /توھان جاوا کي ھڪڙي سلسلي سان برباد نٿا ڪري سگھو: حصو IV -...
Viacheslav
سطح

توھان جاوا کي ھڪڙي سلسلي سان برباد نٿا ڪري سگھو: حصو IV - سڏڻ لائق، مستقبل ۽ دوست

گروپ ۾ شايع ٿيل

تعارف

اسان اڳ ۾ ئي ڏسي چڪا آهيون ته پهرين ڀاڱي ۾ موضوع ڪيئن ٺاهيا ويا آهن . اچو ته ٻيهر ياد رکون. توھان جاوا کي ھڪڙي سلسلي سان خراب نٿا ڪري سگھو: حصو IV - سڏڻ لائق، مستقبل ۽ دوست - 1هڪ ٿريڊ اها Threadشيءِ آهي جيڪا ان ۾ هلندي آهي run، سو اچو ته استعمال ڪريون tutorialspoint java آن لائن ڪمپلر ۽ هيٺ ڏنل ڪوڊ تي عمل ڪريون.
public class HelloWorld {

    public static void main(String []args){
        Runnable task = () -> {
            System.out.println("Hello World");
        };
        new Thread(task).start();
    }
}
ڇا هي واحد آپشن آهي هڪ سلسلي ۾ ڪم هلائڻ لاءِ؟

java.util.concurrent.Callable

اهو ظاهر ٿيو ته java.lang.Runnable کي هڪ ڀاءُ آهي ۽ هن جو نالو آهي java.util.concurrent.Callable ۽ هو جاوا 1.5 ۾ ڄائو هو. اختلاف ڇا آهن؟ جيڪڏهن اسان هن انٽرفيس جي JavaDoc تي هڪ ويجهي نظر وجهون ٿا، اسان ڏسون ٿا ته، برعڪس Runnable، نئون انٽرفيس هڪ طريقو بيان ڪري ٿو callجيڪو نتيجو واپس ڪري ٿو. پڻ، ڊفالٽ طور تي اھو اڇلائي ٿو استثنا. try-catchاهو آهي، اهو اسان کي محفوظ ڪيل استثنا لاء بلاڪ لکڻ جي ضرورت کان بچائي ٿو . اڳ ۾ ئي خراب ناهي، صحيح؟ ھاڻي اسان وٽ Runnableھڪڙو نئون ڪم آھي ان جي بدران:
Callable task = () -> {
	return "Hello, World!";
};
پر ان سان ڇا ڪجي؟ ڇو ته اسان کي ان سلسلي تي هلندڙ ڪم جي ضرورت آهي جيڪو نتيجو ڏئي؟ ظاهر آهي، مستقبل ۾ اسان کي اميد آهي ته عملن جو نتيجو جيڪو مستقبل ۾ ڪيو ويندو. انگريزي ۾ Future - Future. ۽ اتي ھڪڙو انٽرفيس آھي بلڪل ساڳي نالي سان:java.util.concurrent.Future

java.util.concurrent.مستقبل

java.util.concurrent.Future انٽرفيس هڪ API بيان ڪري ٿو ڪمن سان ڪم ڪرڻ لاءِ جن جا نتيجا اسان مستقبل ۾ حاصل ڪرڻ جي رٿابندي ڪريون ٿا: نتيجا حاصل ڪرڻ جا طريقا، اسٽيٽس چيڪ ڪرڻ جا طريقا. اسان Futureان جي نفاذ ۾ دلچسپي رکون ٿا java.util.concurrent.FutureTask . اھو آھي Task، اھو اھو آھي جيڪو عمل ڪيو ويندو Future. هن عمل جي باري ۾ پڻ دلچسپ ڳالهه اها آهي ته اهو لاڳو ٿئي ٿو ۽ Runnable. توھان ھن تي غور ڪري سگھو ٿا ھڪڙي قسم جي اڊاپٽر جي پراڻي ماڊل جي ڪمن سان ڪم ڪرڻ جي سلسلي ۾ ۽ نئين ماڊل (نئين معني ۾ اھو جاوا 1.5 ۾ ظاهر ٿيو). هتي هڪ مثال آهي:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class HelloWorld {

    public static void main(String []args) throws Exception {
        Callable task = () -> {
            return "Hello, World!";
        };
        FutureTask<String> future = new FutureTask<>(task);
        new Thread(future).start();
        System.out.println(future.get());
    }
}
جيئن مثال مان ڏسي سگھجي ٿو، طريقي سان استعمال ڪندي اسان getمسئلي مان نتيجو حاصل ڪندا آهيون task. (!) اهمهن وقت، نتيجو اهو طريقو استعمال ڪندي حاصل ڪيو ويو آهي، getعملدرآمد هم وقت سازي ٿي ويندي آهي. توهان جي خيال ۾ ڪهڙي ميکانيزم هتي استعمال ڪيو ويندو؟ اهو صحيح آهي، ڪو به هم وقت سازي بلاڪ ناهي - تنهن ڪري اسان ڏسنداسين WAITING JVisualVM ۾ نه جيئن monitorيا wait، پر بلڪل ساڳيو park(جيئن ته ميڪانيزم استعمال ڪيو ويو آهي LockSupport).

فنڪشنل انٽرفيس

اڳتي اسان جاوا 1.8 کان ڪلاسز بابت ڳالهائينداسين، تنهنڪري اهو هڪ مختصر تعارف ڪرڻ لاء مفيد ٿيندو. اچو ته هيٺ ڏنل ڪوڊ ڏسو:
Supplier<String> supplier = new Supplier<String>() {
	@Override
	public String get() {
		return "String";
	}
};
Consumer<String> consumer = new Consumer<String>() {
	@Override
	public void accept(String s) {
		System.out.println(s);
	}
};
Function<String, Integer> converter = new Function<String, Integer>() {
	@Override
	public Integer apply(String s) {
		return Integer.valueOf(s);
	}
};
اتي تمام گھڻو غير ضروري ڪوڊ آھي، آھي نه؟ هر هڪ اعلان ڪيل ڪلاس هڪ واحد فنڪشن انجام ڏئي ٿو، پر ان کي بيان ڪرڻ لاء اسين غير ضروري معاون ڪوڊ جو هڪ گروپ استعمال ڪندا آهيون. ۽ جاوا ڊولپر پڻ ائين ئي سوچيو. تنهن ڪري، انهن ”فنڪشنل انٽرفيس“ جو هڪ سيٽ متعارف ڪرايو ( @FunctionalInterface) ۽ فيصلو ڪيو ته هاڻي جاوا پاڻ اسان لاءِ سڀ ڪجهه ”سوچائي“ ڪندو، سواءِ اهم جي:
Supplier<String> supplier = () -> "String";
Consumer<String> consumer = s -> System.out.println(s);
Function<String, Integer> converter = s -> Integer.valueOf(s);
Supplier- فراهم ڪندڙ. ان ۾ ڪو به پيٽرول نه آهي، پر اهو ڪجهه موٽائي ٿو، اهو آهي، اهو ان کي فراهم ڪري ٿو. Consumer- صارف. اهو ان پٽ (پيراميٽر s) جي طور تي ڪجهه وٺندو آهي ۽ ان سان ڪجهه ڪري ٿو، اهو آهي، ڪجهه استعمال ڪري ٿو. اتي هڪ ٻيو فنڪشن آهي. اهو ڪجهه وٺندو آهي جيئن ان پٽ (پيراميٽر s)، ڪجهه ڪري ٿو ۽ ڪجهه موٽائي ٿو. جيئن اسان ڏسون ٿا، عام طور تي استعمال ٿيل آهن. جيڪڏهن توهان کي يقين نه آهي، ته توهان انهن کي ياد ڪري سگهو ٿا ۽ پڙهي سگهو ٿا " جاوا ۾ generics جو نظريو يا مشق ۾ قوس ڪيئن رکڻ ."

مڪمل مستقبل

جيئن وقت گذرندو ويو، جاوا 1.8 هڪ نئون ڪلاس متعارف ڪرايو CompletableFuture. اهو انٽرفيس کي لاڳو ڪري ٿو Future، مطلب ته اسان جو taskمستقبل ۾ عمل ڪيو ويندو ۽ اسان عمل ڪري سگهون ٿا get۽ نتيجو حاصل ڪري سگهون ٿا. پر هو به ڪجهه لاڳو ڪري ٿو CompletionStage. ترجمي مان، ان جو مقصد اڳ ۾ ئي واضح آهي: اهو هڪ خاص اسٽيج آهي حساب جي ڪنهن قسم جي. موضوع جو مختصر تعارف " Introduction to CompletionStage and Completable Future " ۾ ملي سگهي ٿو. اچو ته سڌو سنئون نقطي تي وڃو. اچو ته اسان کي شروع ڪرڻ ۾ مدد لاءِ موجود جامد طريقن جي فهرست تي نظر وجهون: توھان جاوا کي ھڪڙي سلسلي سان خراب نٿا ڪري سگھو: حصو IV - سڏڻ لائق، مستقبل ۽ دوست - 2هتي انهن کي استعمال ڪرڻ جا اختيار آهن:
import java.util.concurrent.CompletableFuture;
public class App {
    public static void main(String []args) throws Exception {
        // CompletableFuture уже содержащий результат
        CompletableFuture<String> completed;
        completed = CompletableFuture.completedFuture("Просто meaning");
        // CompletableFuture, запускающий (run) новый поток с Runnable, поэтому он Void
        CompletableFuture<Void> voidCompletableFuture;
        voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("run " + Thread.currentThread().getName());
        });
        // CompletableFuture, запускающий новый поток, результат которого возьмём у Supplier
        CompletableFuture<String> supplier;
        supplier = CompletableFuture.supplyAsync(() -> {
            System.out.println("supply " + Thread.currentThread().getName());
            return "Значение";
        });
    }
}
جيڪڏهن اسان هن ڪوڊ کي هلائيندا آهيون، اسان ڏسندا سين ته تخليق ۾ CompletableFutureپوري زنجير کي شروع ڪرڻ شامل آهي. تنهن ڪري، جڏهن ته Java8 کان SteamAPI سان ڪجهه هڪجهڙائي آهي، اهو انهن طريقن جي وچ ۾ فرق آهي. مثال طور:
List<String> array = Arrays.asList("one", "two");
Stream<String> stringStream = array.stream().map(value -> {
	System.out.println("Executed");
	return value.toUpperCase();
});
هي جاوا 8 اسٽريم ايپي جو هڪ مثال آهي (توهان ان بابت وڌيڪ پڙهي سگهو ٿا هتي " جاوا 8 اسٽريم API گائيڊ تصويرون ۽ مثالن ۾ "). جيڪڏهن توهان هن ڪوڊ کي هلائيندا آهيو، اهو Executedظاهر نه ٿيندو. اهو آهي، جڏهن جاوا ۾ هڪ وهڪرو ٺاهي، وهڪرو فوري طور تي شروع نه ڪندو آهي، پر انتظار ڪري ٿو جيستائين ان مان هڪ قدر گهربل هجي. پر CompletableFutureاهو فوري طور تي عمل لاءِ سلسلو شروع ڪري ٿو، بغير حساب جي قيمت لاءِ پڇڻ جو انتظار ڪرڻ جي. مان سمجهان ٿو ته اهو سمجهڻ ضروري آهي. تنهنڪري اسان وٽ مڪمل مستقبل آهي. اسان هڪ زنجير ڪيئن ٺاهي سگهون ٿا ۽ اسان وٽ ڇا مطلب آهي؟ اچو ته فنڪشنل انٽرفيس جي باري ۾ ياد رکون جن بابت اسان اڳ ۾ لکيو آهي.
  • اسان وٽ هڪ فنڪشن آهي ( Function) جيڪو A وٺي ٿو ۽ B واپس ڪري ٿو. ان جو هڪ طريقو آهي - apply(لاڳو).
  • اسان وٽ ھڪڙو صارف آھي ( Consumer) جيڪو قبول ڪري ٿو A ۽ ڪجھھ واپس نٿو ڪري ( باطل ). اهو صرف هڪ طريقو آهي - accept(قبول).
  • اسان وٽ ڪوڊ آھي ھڪڙي سلسلي تي ھلندو آھي Runnableجيڪو قبول يا واپس نٿو ڪري. ان جو ھڪڙو طريقو آھي - run(رن).
ياد رکڻ لاء ٻي شيء اها آهي ته CompletalbeFutureان جي ڪم ۾ اهو Runnableصارفين ۽ افعال استعمال ڪري ٿو. هن کي ڏنو، توهان هميشه ياد ڪري سگهو ٿا ته توهان CompletableFutureهي ڪري سگهو ٿا:
public static void main(String []args) throws Exception {
        AtomicLong longValue = new AtomicLong(0);
        Runnable task = () -> longValue.set(new Date().getTime());
        Function<Long, Date> dateConverter = (longvalue) -> new Date(longvalue);
        Consumer<Date> printer = date -> {
            System.out.println(date);
            System.out.flush();
        };
        // CompletableFuture computation
        CompletableFuture.runAsync(task)
                         .thenApply((v) -> longValue.get())
                         .thenApply(dateConverter)
                         .thenAccept(printer);
}
طريقن جا نسخا thenRunآهن . _ هن جو مطلب آهي ته اهي مرحلا هڪ نئين سلسلي ۾ execute ڪيو ويندو. اهو هڪ خاص تلاءَ مان ورتو ويندو، تنهنڪري اهو اڳ ۾ معلوم ناهي ته اهو ڪهڙي قسم جو وهڪرو هوندو، نئون يا پراڻو. اهو سڀ ان تي منحصر آهي ته ڪم ڪيترو ڏکيو آهي. انهن طريقن کان علاوه، ٽي وڌيڪ دلچسپ امڪان آهن. وضاحت لاءِ، اچو ته تصور ڪريون ته اسان وٽ هڪ خاص خدمت آهي جيڪا ڪنهن هنڌ تان پيغام وصول ڪري ٿي ۽ ان ۾ وقت لڳندو آهي: thenApplythenAcceptAsync
public static class NewsService {
	public static String getMessage() {
		try {
			Thread.currentThread().sleep(3000);
			return "Message";
		} catch (InterruptedException e) {
			throw new IllegalStateException(e);
		}
	}
}
هاڻي اچو ته ٻين خاصيتن تي نظر رکون جيڪي CompletableFuture. اسان نتيجن کي CompletableFutureٻئي جي نتيجي سان گڏ ڪري سگھون ٿا CompletableFuture:
Supplier newsSupplier = () -> NewsService.getMessage();

CompletableFuture<String> reader = CompletableFuture.supplyAsync(newsSupplier);
CompletableFuture.completedFuture("!!")
				 .thenCombine(reader, (a, b) -> b + a)
				 .thenAccept(result -> System.out.println(result))
				 .get();
اها ڳالهه نوٽ ڪرڻ جي قابل آهي ته ڊفالٽ طور ٿريڊز ڊيمون ٿريڊز هوندا، تنهن ڪري وضاحت لاءِ get، اسان نتيجن جو انتظار ڪرڻ لاءِ استعمال ڪريون ٿا. ۽ اسان نه رڳو گڏ ڪري سگهون ٿا (گڏجي)، پر واپسي به CompletableFuture:
CompletableFuture.completedFuture(2L)
				.thenCompose((val) -> CompletableFuture.completedFuture(val + 2))
                               .thenAccept(result -> System.out.println(result));
هتي مان اهو نوٽ ڪرڻ چاهيان ٿو ته اختصار لاء، طريقو استعمال ڪيو ويو CompletableFuture.completedFuture. اهو طريقو ڪو نئون سلسلو نٿو ٺاهي، تنهنڪري باقي زنجير ساڳئي سلسلي ۾ جاري ڪيو ويندو، جنهن ۾ ان کي سڏيو ويندو هو completedFuture. اتي پڻ ھڪڙو طريقو آھي thenAcceptBoth. اهو تمام گهڻو ملندو آهي accept، پر جيڪڏهن thenAcceptاهو قبول ڪري ٿو consumer، پوء thenAcceptBothاهو قبول ڪري ٿو ٻيو CompletableStage+ انپٽ طور BiConsumer، اهو آهي consumer، جيڪو 2 ذريعن کي ان پٽ طور قبول ڪري ٿو، هڪ نه. لفظ سان گڏ هڪ ٻيو دلچسپ امڪان آهي Either: توھان جاوا کي ھڪڙي سلسلي سان برباد نٿا ڪري سگھو: حصو IV - سڏڻ لائق، مستقبل ۽ دوست - 3اهي طريقا هڪ متبادل کي قبول ڪن ٿا CompletableStage۽ انهن تي عمل ڪيو ويندو CompletableStageجيڪو پهرين تي عمل ڪيو ويندو. ۽ مان هن جائزي کي هڪ ٻي دلچسپ خصوصيت سان ختم ڪرڻ چاهيندس CompletableFuture- غلطي سنڀالڻ.
CompletableFuture.completedFuture(2L)
				 .thenApply((a) -> {
					throw new IllegalStateException("error");
				 }).thenApply((a) -> 3L)
				 //.exceptionally(ex -> 0L)
				 .thenAccept(val -> System.out.println(val));
هي ڪوڊ ڪجھ به نه ڪندو، ڇاڪاڻ ته ... هڪ استثنا اڇلايو ويندو ۽ ڪجھ به نه ٿيندو. پر جيڪڏهن اسان غير تبصرو ڪريون ٿا exceptionally، ته پوء اسان رويي جي وضاحت ڪريون ٿا. مان هن موضوع تي CompletableFutureهيٺ ڏنل وڊيو ڏسڻ جي صلاح ڏيان ٿو : منهنجي عاجز راء ۾، اهي وڊيوز انٽرنيٽ تي سڀ کان وڌيڪ بصري آهن. انهن مان اهو واضح ٿيڻ گهرجي ته اهو سڀ ڪيئن ڪم ڪري ٿو، اسان وٽ ڪهڙو هٿيار آهي ۽ اهو سڀ ڪجهه ڇو ضروري آهي.

نتيجو

اميد آهي ته اهو هاڻي واضح ٿي ويو آهي ته ڪيئن ٿريڊس استعمال ڪري سگھجن ٿيون حساب ڪتاب ڪرڻ کان پوءِ. اضافي مواد: #وياچسلاو
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION