CodeGym /جاوا بلاگ /Random-SD /گڏو گڏ بهتر: جاوا ۽ ٿريڊ ڪلاس. حصو IV - سڏڻ لائق، مستقبل،...
John Squirrels
سطح
San Francisco

گڏو گڏ بهتر: جاوا ۽ ٿريڊ ڪلاس. حصو IV - سڏڻ لائق، مستقبل، ۽ دوست

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

تعارف

حصو I ۾ ، اسان جائزو ورتو ته موضوع ڪيئن ٺاهيا ويا آهن. اچو ته هڪ دفعو ٻيهر ياد ڪريون. گڏو گڏ بهتر: جاوا ۽ ٿريڊ ڪلاس.  حصو IV - قابل، مستقبل، ۽ دوست - 1هڪ ڌاڳو ٿريڊ ڪلاس جي نمائندگي ڪري ٿو، جنهن جي run()طريقي کي سڏيو ويندو آهي. سو اچو ته Tutorialspoint آن لائن جاوا ڪمپلر استعمال ڪريون ۽ ھيٺ ڏنل ڪوڊ تي عمل ڪريون.
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 ۾ دنيا ۾ آيو. اختلاف ڇا آهن؟ جيڪڏهن توهان هن انٽرفيس لاءِ جاواڊڪ تي ويجهڙائي سان ڏسندا آهيون، اسان ڏسون ٿا ته، برعڪس Runnable، نئون انٽرفيس هڪ call()طريقو بيان ڪري ٿو جيڪو نتيجو واپس ڪري ٿو. پڻ، اھو ڊفالٽ طور استثنا اڇلائي ٿو. اھو آھي، اھو اسان کي بچائيندو آھي try-catchبلاڪ ڪرڻ کان سواء چيڪ ٿيل استثنا لاء. خراب ناهي، صحيح؟ ھاڻي اسان وٽ ھڪڙو نئون ڪم آھي بدران Runnable:
Callable task = () -> {
	return "Hello, World!";
};
پر اسان ان سان ڇا ڪريون؟ اسان کي ڇو ضرورت آھي ھڪڙي ٽاسڪ تي ھلندڙ ھڪڙي سلسلي تي جيڪو نتيجو ڏئي ٿو؟ ظاهر آهي، مستقبل ۾ ڪيل ڪنهن به ڪارناما لاءِ، اسان اميد رکون ٿا ته مستقبل ۾ انهن عملن جو نتيجو. ۽ اسان وٽ ھڪڙو انٽرفيس آھي جنھن سان لاڳاپيل نالو:java.util.concurrent.Future

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

java.util.concurrent.Future انٽرفيس هڪ API جي وضاحت ڪري ٿو ڪمن سان ڪم ڪرڻ لاءِ جن جا نتيجا اسان مستقبل ۾ حاصل ڪرڻ جي رٿابندي ڪريون ٿا: نتيجا حاصل ڪرڻ جا طريقا، ۽ اسٽيٽس چيڪ ڪرڻ جا طريقا . جي حوالي سان Future، اسان جاوا.util.concurrent.FutureTask ڪلاس ۾ ان جي نفاذ ۾ دلچسپي رکون ٿا. هي اهو آهي "ٽاسڪ" جنهن تي عمل ڪيو ويندو 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ڪم مان نتيجو حاصل ڪرڻ جو طريقو استعمال ڪندا آهيون. نوٽ:جڏهن توهان طريقي سان نتيجو حاصل ڪريو ٿا get()، عملدرآمد هم وقت ٿي ويندو آهي! توهان جي خيال ۾ ڪهڙي ميکانيزم هتي استعمال ڪيو ويندو؟ سچ، ڪو به هم وقت سازي بلاڪ ناهي. ان ڪري اسان نه ڏسنداسين WAITING JVisualVM ۾ a 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واپرائڻ. اهو هڪ ان پٽ (هڪ دليل) طور ڪجهه وٺندو آهي ۽ ان سان ڪجهه ڪندو آهي. استدلال اهو آهي ته اهو ڇا کائي ٿو. پوءِ اسان وٽ به آهي Function. اهو ان پٽ (دليل) وٺندو آهي، ڪجهه ڪري ٿو، ۽ ڪجهه موٽائي ٿو. توهان ڏسي سگهو ٿا ته اسان فعال طور تي عام استعمال ڪري رهيا آهيون. جيڪڏهن توهان کي يقين نه آهي، ته توهان پڙهي ريفريشر حاصل ڪري سگهو ٿا " Generics in Java: how to use angled brackets in practice ".

مڪمل مستقبل

وقت گذري ويو ۽ هڪ نئون ڪلاس CompletableFutureظاهر ٿيو جاوا 1.8 ۾. اهو Futureانٽرفيس کي لاڳو ڪري ٿو، يعني اسان جا ڪم مستقبل ۾ مڪمل ڪيا ويندا، ۽ اسان get()نتيجو حاصل ڪرڻ لاءِ ڪال ڪري سگهون ٿا. پر اهو پڻ CompletionStageانٽرفيس کي لاڳو ڪري ٿو. نالو اهو سڀ ڪجهه چوي ٿو: اهو ڪجهه حسابن جو هڪ خاص مرحلو آهي. موضوع جو مختصر تعارف هتي نظرثاني ۾ ملي سگهي ٿو: مڪمل ٿيڻ واري اسٽيج جو تعارف ۽ مڪمل مستقبل. اچو ته صحيح نقطي تي وڃو. اچو ته موجود جامد طريقن جي فهرست تي نظر رکون جيڪي اسان کي شروع ڪرڻ ۾ مدد ڏين ٿيون: گڏو گڏ بهتر: جاوا ۽ ٿريڊ ڪلاس.  حصو IV - قابل، مستقبل، ۽ دوست - 2هتي انهن کي استعمال ڪرڻ جا اختيار آهن:
import java.util.concurrent.CompletableFuture;
public class App {
    public static void main(String[] args) throws Exception {
        // A CompletableFuture that already contains a Result
        CompletableFuture<String> completed;
        completed = CompletableFuture.completedFuture("Just a value");
        // A CompletableFuture that runs a new thread from Runnable. That's why it's Void
        CompletableFuture<Void> voidCompletableFuture;
        voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("run " + Thread.currentThread().getName());
        });
        // A CompletableFuture that starts a new thread whose result we'll get from a Supplier
        CompletableFuture<String> supplier;
        supplier = CompletableFuture.supplyAsync(() -> {
            System.out.println("supply " + Thread.currentThread().getName());
            return "Value";
        });
    }
}
جيڪڏهن اسان هن ڪوڊ تي عمل ڪريون ٿا، اسان ڏسنداسين ته هڪ ٺاهڻ ۾ 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 جي اسٽريم API جو هڪ مثال آهي. جيڪڏهن توهان هن ڪوڊ کي هلائيندا آهيو، توهان ڏسندا ته "Executed" ظاهر نه ٿيندو. ٻين لفظن ۾، جڏهن جاوا ۾ هڪ وهڪرو ٺاهيو ويندو آهي، اهو وهڪرو فوري طور تي شروع نه ٿيندو آهي. ان جي بدران، اهو انتظار ڪري ٿو ته ڪنهن کي ان کان قيمت چاهيندو آهي. پر CompletableFutureپائيپ لائين کي فوري طور تي عمل ڪرڻ شروع ڪري ٿو، بغير ڪنهن جو انتظار ڪرڻ جي ان جي قيمت لاء پڇي. مان سمجهان ٿو ته اهو سمجهڻ ضروري آهي. ايس او، اسان وٽ هڪ آهي CompletableFuture. اسان هڪ پائپ لائن (يا زنجير) ڪيئن ٺاهي سگهون ٿا ۽ اسان وٽ ڪهڙو ميڪانيزم آهي؟ انهن فنڪشنل انٽرفيس کي ياد ڪريو جن بابت اسان اڳ ۾ لکيو آهي.
  • اسان وٽ ھڪڙو آھي Functionجيڪو ھڪڙو A وٺي ٿو ۽ ھڪڙو B واپس ڪري ٿو. اھو ھڪڙو طريقو آھي: apply().
  • اسان وٽ ھڪڙو آھي Consumerجيڪو ھڪڙو A وٺندو آھي ۽ ڪجھھ واپس نه ڪندو آھي (خالي). اهو هڪ واحد طريقو آهي: accept().
  • اسان وٽ آهي Runnable، جيڪو سلسلو تي هلندو آهي، ۽ ڪجهه به نه وٺندو آهي ۽ ڪجهه به واپس نه ڪندو آهي. اهو هڪ واحد طريقو آهي: run().
ياد رکڻ لاء ايندڙ شيء اهو آهي ته CompletableFutureاستعمال ڪري ٿو Runnable، Consumers۽ Functionsان جي ڪم ۾. انهي جي مطابق، توهان هميشه ڄاڻو ٿا ته توهان هيٺيان ڪري سگهو ٿا 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()جا "Async" ورجن آھن. مطلب ته اهي مرحلا هڪ مختلف سلسلي ۾ مڪمل ٿيندا. هي ٿريڊ هڪ خاص تلاءَ مان ورتو ويندو — تنهنڪري اسان کي اڳ ۾ خبر نه پوندي ته اهو نئون يا پراڻو ٿريڊ هوندو. اهو سڀ ان تي منحصر آهي ته ڪئين ڪمپيوٽيشنل-گهڻي ڪم آهن. انهن طريقن کان علاوه، ٽي وڌيڪ دلچسپ امڪان آهن. وضاحت لاءِ، اچو ته تصور ڪريون ته اسان وٽ هڪ خاص خدمت آهي جيڪا ڪنهن هنڌ کان ڪجهه قسم جو پيغام وصول ڪري ٿي - ۽ اهو وقت وٺندو آهي: thenApply()thenAccept()
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()نتيجن جو انتظار ڪرڻ لاءِ استعمال ڪريون ٿا. نه رڳو اسان گڏ ڪري سگهون ٿا CompletableFutures، اسان پڻ واپس ڪري سگهون ٿا CompletableFuture:
CompletableFuture.completedFuture(2L)
				.thenCompose((val) -> CompletableFuture.completedFuture(val + 2))
                               .thenAccept(result -> System.out.println(result));
هتي مان اهو نوٽ ڪرڻ چاهيان ٿو ته اهو CompletableFuture.completedFuture()طريقو اختصار لاءِ استعمال ڪيو ويو هو. اهو طريقو نئون ٿريڊ نٿو ٺاهي، ان ڪري باقي پائيپ لائين ان ئي ٿريڊ تي هلايو ويندو جتي completedFutureسڏيو ويو هو. ھڪڙو طريقو پڻ آھي thenAcceptBoth(). اهو تمام گهڻو ملندڙ جلندڙ آهي accept()، پر جيڪڏهن thenAccept()قبول ڪري ٿو a Consumer، thenAcceptBoth()ٻئي CompletableStage+ کي BiConsumerان پٽ طور قبول ڪري ٿو، يعني a 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));
هي ڪوڊ ڪجھ به نه ڪندو، ڇاڪاڻ ته اتي هڪ استثنا هوندو ۽ ٻيو ڪجهه به نه ٿيندو. پر "غير معمولي" بيان کي رد ڪندي، اسان متوقع رويي جي وضاحت ڪريون ٿا. جي ڳالهائيندي CompletableFuture، مان پڻ توهان کي هيٺين وڊيو ڏسڻ جي صلاح ڏيان ٿو: منهنجي عاجز راءِ ۾، اهي انٽرنيٽ تي سڀ کان وڌيڪ وضاحتي وڊيوز مان آهن. انهن کي اهو واضح ڪرڻ گهرجي ته اهو سڀ ڪيئن ڪم ڪري ٿو، اسان وٽ ڪهڙي ٽول ڪٽ موجود آهي، ۽ اهو سڀ ڪجهه ڇو گهربل آهي.

نتيجو

اميد آهي ته، اهو هاڻي واضح ٿي ويو آهي ته توهان مڪمل ٿيڻ کان پوءِ حساب ڪتاب حاصل ڪرڻ لاءِ موضوع ڪيئن استعمال ڪري سگهو ٿا. اضافي مواد: گڏو گڏ بهتر: جاوا ۽ ٿريڊ ڪلاس. حصو I - عملدرآمد جا موضوع گڏ ڪري بهتر: جاوا ۽ ٿريڊ ڪلاس. حصو II - هم وقت سازي بهتر گڏجي: جاوا ۽ ٿريڊ ڪلاس. حصو III - رابطي بهتر گڏجي: جاوا ۽ ٿريڊ ڪلاس. حصو V - ايگزيڪيوٽر، ٿريڊ پول، فورڪ / شامل ٿيڻ بهتر گڏجي: جاوا ۽ ٿريڊ ڪلاس. حصو VI - فائر پري!
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION