ورود

View Full Version : مشکل در برگرداندن مقادیر نخها در Callable



mostafa272
سه شنبه 16 اردیبهشت 1393, 18:05 عصر
با سلام

من یک برنامه کلاینت سرور دارم که باید قسمت سرور دستورات به صورت چند نخی اجرا بشه. یه تابع به نام parseExecution دارم که مقدار هر دستور را محاسبه میکنه و بر می گردونه. هر رشته ای که از طرف کلاینت ارسال میشه می تونه شامل چند دستور باشه. من این دستورات را جدا می کنم و درون آرایه ای میریزم به نام elements. بعد با حلقه for(String str:elements) یک شی از کلاس thread که اینترفیس Callable رو پیاده سازی میکنه میسازم که str رو به عنوان پارامتر ورودی میگیره. اما نمیدونم چرا وقتی می خوام با متد get شی از نوع Future مقادیر رو برگردونم استثنای null pointer به وجود میاد و چیزی برگردونده نمیشه.

اگر کسی با Callable و چند نخی کار کرده لطفا راهنمایی کنه.

با تشکر

vahid-p
سه شنبه 16 اردیبهشت 1393, 19:01 عصر
کدتون رو بذارید.

mostafa272
چهارشنبه 17 اردیبهشت 1393, 15:18 عصر
کلاس چند نخی:


public class MultiThreadMathServer extends mathserver implements Callable {
protected String parameter;
public String final_result;
public MultiThreadMathServer(String parameter) {
this.parameter = parameter;
}
public String call() throws Exception {
Thread.sleep(1000);
//return the thread name executing this callable task
return parseExecution(parameter);
}
public String getValue(){
return final_result;
}
}


تابعی که بعد از ایجاد اتصال سوکت فراخوانی می شود:


try {
String result1="";
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// read the message from client and parse the execution
String line = reader.readLine();
String [] elements = line.split("#");
ExecutorService executor = Executors.newFixedThreadPool(10);
//create a list to hold the Future object associated with Callable
List<Future<String>> list = new ArrayList<Future<String>>();
for(String s:elements)
{
MultiThreadMathServer server = new MultiThreadMathServer(s);
Future<String> future = executor.submit(server);
list.add(future);

}
for(Future<String> fut : list){
try {

result1=fut.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
// write the result back to the client
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
writer.write("Thread-"+Thread.currentThread().getId()+" :"+result1);
writer.newLine();
writer.flush();
// close the stream
reader.close();
writer.close();
}
catch (Exception e) {
e.printStackTrace();
}

vahid-p
جمعه 19 اردیبهشت 1393, 01:18 صبح
چرا از ExecutorService استفاده کنی؟ تا اونجایی که من اطلاعات ناقصم میگه این بیشتر برای تبدیل thread های معمولی به چنین حالتی ازش استفاده میشه فکر کنم! مطمئن نیستم. در این مورد نظری نمیدم.
ولی در عوض میتونی از این روش استفاده کنی و خیلی راحتتر و کدت هم تر و تمیز تر میشه :


import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MultiThreadMathServer {

public MultiThreadMathServer() throws InterruptedException, ExecutionException {
String line = "abcdef1ghijkl2mnopqr3stuvw4xyz";
String[] elements = line.split("\\d+");
ArrayList<FutureTask<String>> list = new ArrayList<>();
for (String element : elements) {
list.add(new FutureTask<>(new MyThread(element)));
}
for (FutureTask<String> f : list) {
f.run();
}
for (FutureTask<String> f : list) {
System.out.println(f.get());
}
}

private class MyThread implements Callable<String> {
private final String parameter;

public MyThread(String parameter) {
this.parameter = parameter;
}

@Override
public String call() throws Exception {
return parseExecution(parameter);
}

private String parseExecution(String parameter) {
//TO-DO
return parameter;
}
}
}


هر MyThread که Callable رو پیاده سازی میکنه، رو تو FutureTask ذخیره میکنی و اونوقت تو یه حلقه همه FutureTask ها رو run میکنی که خودش تابع call رو صدا میزنه و نتایج برگشت داده شده تو خود FutureTask ها ذخیره میشن. حالا هر وقت میخوای get کن ( تا وقتی که نتیجه برگشت داده نشده، صبر میکنه و وقتی گرفت بعدا ادامه میده، یعنی نتیجه get همیشه معتبر است مگر اینکه exception بده که متوجه میشی ). البته تقریبا چیزی که شما نوشتید، همین هست، ولی FutureTask کار رو راحت کرده. مثلا تو یکی از کانتسراکتور هاش میبینیم :

public FutureTask(Runnable runnable, V result) {
sync = new Sync(Executors.callable(runnable, result));
}

که خودش یه جورایی حرف شما رو زده، Runnable رو میگیره و جواب رو تو یه آرگومان دیگه ذخیره میکنه. از این طریق return هم نمیخواد. و از طرفی خودش از Executors استفاده کرده.

در پرانتز : نیازی به استفاده از ArrayList هم برای FutureTask نیست چون سایزش مشخصه، به تعداد Element هست که با آرایه هم اشکالی پیش نمیاد. البته ربطی به بحث نداشت :)

اگر باز اررور داد که قاعدتا نباید ارروری بده، کد parseExecution رو بذارید چون اگه مشکلی باشه از اونجاست احتمالا.
موفق باشید.