ارسال پارامتر به نخ های جاوا — از صفر تا صد

در این راهنما به بررسی گزینههای مختلف برای ارسال پارامتر به نخ های جاوا میپردازیم. ابتدا باید اشاره کنیم که برای ایجاد «نخ» (Thread) در جاوا میتوان یک Runnable یا Callable پیادهسازی کرد. برای اجرای یک نخ، میتوانیم با ارسال یک وهله از Runnable اقدام به فراخوانی Thread#start بکنیم. همچنین میتوانیم با ارسال یک ExecutorService از یک «استخر نخ» (Thread Pool) بهره بگیریم.
اما مشکل اینجا است که هیچ کدام از این رویکردها، پارامترهای اضافی قبول نمیکنند. در این راهنما با روش ارسال پارامتر به یک نخ آشنا میشویم.
ارسال پارامتر در سازنده
نخستین روش برای ارسال یک پارامتر به نخ این است که Runnable یا Callable خود را در سازنده ارائه کنیم.
در ادامه یک AverageCalculator ایجاد میکنیم که یک آرایه از اعداد میپذیرد و میانگین آنها را بازگشت میدهد:
public class AverageCalculator implements Callable<Double> { int[] numbers; public AverageCalculator(int... numbers) { this.numbers = numbers == null ? new int[0] : numbers; } @Override public Double call() throws Exception { return IntStream.of(numbers).average().orElse(0d); } }
در ادامه برخی اعداد را در اختیار نخ محاسبهکننده میانگین قرار میدهیم و خروجی آن را اعتبارسنجی میکنیم:
@Test public void whenSendingParameterToCallable_thenSuccessful() throws Exception { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Double> result = executorService.submit(new AverageCalculator(1, 2, 3)); try { assertEquals(2.0, result.get().doubleValue()); } finally { executorService.shutdown(); } }
توجه کنید که دلیل عملکرد صحیح این کد آن است که پیش از اجرای نخ، حالت را در اختیار کلاس خود قرار دادهایم.
ارسال پارامتر از طریق یک کلوژر
روش دیگری که برای ارسال پارامتر به یک نخ وجود دارد، ایجاد یک بستار یا کلوژر (Closure) است.
منظور از کلوژر، دامنهای است که برخی از خصوصیات دامنه والد خود را به ارث میبرد. قبلاً این وضعیت را در مورد لامبداها و کلاسهای داخلی بینام مشاهده کردهایم. در ادامه مثال قبلی را بسط میدهیم و دو نخ دیگر ایجاد میکنیم. ابتدا میانگین را محاسبه میکنیم:
executorService.submit(() -> IntStream.of(numbers).average().orElse(0d));
سپس، عملیات جمع را انجام میدهیم:
executorService.submit(() -> IntStream.of(numbers).sum());
در ادامه میبینید که چطور میتوانیم پارامتر یکسانی را به هر دو نخ ارسال کرده و نتیجه را دریافت کنیم:
@Test public void whenParametersToThreadWithLamda_thenParametersPassedCorrectly() throws Exception { ExecutorService executorService = Executors.newFixedThreadPool(2); int[] numbers = new int[] { 4, 5, 6 }; try { Future<Integer> sumResult = executorService.submit(() -> IntStream.of(numbers).sum()); Future<Double> averageResult = executorService.submit(() -> IntStream.of(numbers).average().orElse(0d)); assertEquals(Integer.valueOf(15), sumResult.get()); assertEquals(Double.valueOf(5.0), averageResult.get()); } finally { executorService.shutdown(); } }
نکته مهمی که باید به خاطر داشته باشید این است که پارامترها باید به طرز مؤثری به صورت final باشند، چون در غیر این صورت امکان ارسال آنها به کلوژر وجود نخواهد داشت. ضمناً این قواعد همزمان که در اینجا استفاده کردیم در همه موارد دیگر هم باید برقرار باشد. اگر یک مقدار در آرایه numbers تغییر یابد و نخها هم در حال اجرا باشند، هیچ تضمینی وجود ندارد که بدون نوعی همگامسازی بتوانند آن را ببینند.
برای جمعبندی باید اشاره کنیم که در صورت استفاده از نسخههای قدیمیتر جاوا، میتوان از یک کلاس داخلی بینام نیز به این منظور استفاده کرد:
final int[] numbers = { 1, 2, 3 }; Thread parameterizedThread = new Thread(new Callable<Double>() { @Override public Double call() { return calculateTheAverage(numbers); } }); parameterizedThread.start();
سخن پایانی
در این مقاله به بررسی گزینههای مختلف موجود برای ارسال پارامترها به نخهای جاوا پرداختیم. همه کدهای بررسیشده در این مقاله را میتوانید در این ریپوی گیتهاب (+) ملاحظه کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای جاوا
- مجموعه آموزشهای برنامهنویسی
- گنجینه آموزشهای جاوا (Java)
- ۱۰ مفهوم اصلی زبان جاوا که هر فرد مبتدی باید بداند
- زبان برنامه نویسی جاوا (Java) — از صفر تا صد
==