基本上我有一个ExecutorService使用的小线程类和一个固定的线程池。每个线程实例化我的线程类,并且调用call方法,效果很好!
但是我真的需要调用另一个类(通过实例化或静态方法)来处理&在call方法中返回一些数据,但是在尝试这个时,我可以理解得到concurrent.ExecutionException以及相关的方法。
我认为在这里粘贴我的所有代码会更容易,请注意它非常粗糙
MainController
package com.multithreading.excutorservice;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class MainController {
private static List<String> urls;
public static void main(String[] args) {
populateList();
// futures to retrieve task results
List<Future<ArrayList>> futures = new ArrayList<Future<ArrayList>>();
// results
List<ArrayList> results = new ArrayList<ArrayList>();
// pool with 5 threads
ExecutorService exec = Executors.newFixedThreadPool(5);
// enqueue tasks
for(String url: urls) {
futures.add(exec.submit(new ThreadTask(url)));
}
// attempt to move ArrayLists within Future<ArrayList> into a normal ArrayList
for(Future<ArrayList> future: futures) {
try {
results.add(future.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// for(ArrayList<String> s: results) {
// System.out.println(s);
// }
}
private static void populateList() {
urls = new ArrayList<String>();
urls.add("http://www.google.com");
urls.add("http://www.msn.co.uk");
urls.add("http://www.yahoo.co.uk");
urls.add("http://www.google.com");
urls.add("http://www.msn.co.uk");
urls.add("http://www.yahoo.co.uk");
}
}
ThreadTask
package com.multithreading.excutorservice;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
public class ThreadTask implements Callable<ArrayList> {
private String url;
HtmlParser parseHtml;
public ThreadTask(String url) {
this.url = url;
}
public ArrayList call() {
int counter = 0;
String html = null;
try {
URL myUrl = new URL(url);
BufferedReader reader = new BufferedReader(new InputStreamReader(myUrl.openStream()));
while ((html = reader.readLine()) != null) {
//counter += inputLine.length();
html += html;
}
}
catch (Exception ex) {
System.out.println(ex.toString());
}
ArrayList<String> storeLinks = new ArrayList<String>();
HtmlParser par = new HtmlParser();
storeLinks = par.returnNewUrls(html);
// for(String s: parseHtml) {
// System.out.println(s);
// }
//returns an ArrayList of URLS which is stored in a List<Future<ArrayList>> temporarily
return storeLinks;
}
}
的HTMLParser
package com.multithreading.excutorservice;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlParser {
private final String regex_links = "\\s*(?i)href\\s*=\\s*(\"([^\"]*\")|'[^']*'|([^'\">\\s]+))";
private ArrayList<String> extractedUrls;
public ArrayList<String> returnNewUrls (String data) {
extractedUrls = new ArrayList<String>();
Pattern p = Pattern.compile(regex_links);
Matcher m = p.matcher(data);
System.out.println("Test");
while (m.find()) {
System.out.println("Test");
extractedUrls.add(m.group(1));
}
return getLinks();
}
//returns the links
public ArrayList getLinks() {
return extractedUrls;
}
}
答案 0 :(得分:1)
你在做一些非常奇怪的事情。多个线程正在访问相同的static extractedUrls字段,每次调用returnNewUrls都会创建一个新字段。在returnNewUrls方法中,创建一个新的ArrayList,它是方法范围的本地。有点像:
public static ArrayList<String> returnNewUrls(String data) {
ArrayList<String> urls = new ArrayList<String>();
addStuffToUrlsList();
return urls;
}
另一件事 - 不是错误,但是你做了不必要的事情 - 在调用方法中,如果你只是分配给变量,则不需要创建新的列表:
ArrayList<String> parseHtml = new ArrayList<String>();
parseHtml = HtmlParser.returnNewUrls(html);
这样更好:
ArrayList<String> parseHtml = HtmlParser.returnNewUrls(html);
答案 1 :(得分:0)
你有几个并发任务,但他们使用相同的变量HtmlParser.extractedUrls?没有任何同步。在returnNewUrls方法中移动此变量。 BTW即使没有并发性,也不鼓励使用静态变量,特别是在类似的情况下,可以很容易地用局部变量替换它。