我写了一个小的Java程序来从网站上抓取信息。我基本上下载了包含本月新闻ID的excel文件,并将它们添加到查询表中的数据库中。之后,我通过请求带有前面的id作为参数的页面来开始抓取,使用jsoup解析页面并将信息保存到数据库中的另一个表中。
除了ConnectionManager
类
public class ConnectionManager {
public static final int MAX_CONNECTIONS = 50;
private ArrayList<Runnable> mActiveThreads = new ArrayList<Runnable>();
private ArrayList<Runnable> mQueuedRunnables = new ArrayList<Runnable>();
private static ConnectionManager instance;
//Singleton
public static ConnectionManager getInstance() {
if (instance == null) {
System.out.println("Started Connection mQueuedRunnables " + new Date());
instance = new ConnectionManager();
}
return instance;
}
//Adds new Runnable to the queue
public void push(Runnable runnable) {
mQueuedRunnables.add(runnable);
if (mActiveThreads.size() < MAX_CONNECTIONS)
startNext();
}
//Starts a Thread with the next Runnable in the queue
private void startNext() {
if (!mQueuedRunnables.isEmpty()) {
Runnable next = mQueuedRunnables.get(0);
mQueuedRunnables.remove(0);
mActiveThreads.add(next);
Thread thread = new Thread(next);
thread.start();
} else if (mActiveThreads.size() == MAX_CONNECTIONS) {
System.out.println("FINISHED " + new Date());
}
}
//Callback method called when a Thread finishes its execution,
//Runnable is removed from queue and startNext() called
public void didComplete(Runnable runnable) {
synchronized(mActiveThreads) {
mActiveThreads.remove(runnable);
if (mActiveThreads.size() < MAX_CONNECTIONS)
startNext();
}
}
}
对于我需要做的每个连接,我push()
所有Runnables
,这应该有50个永久运行Threads
,直到队列清空。正如您所看到的,它保留了两个Lists
:一个用于队列,另一个用于活动Threads
。 Runnables
我push()
只是简单Runnables
,它会生成HttpURLConnection
,解析HTML
并将数据插入数据库。
据我所知,这应该可行,但我怀疑某处存在死锁,因为在某些时候,活动Threads
开始丢失,直到它停止。我一直在调试代码,发现当mActiveThreads
保持为50时,JVM中的实际活动Threads
会越来越低。
我所做的最新更改是synchronized
阻止,但它似乎没有任何帮助。有人能指出我代码失败的地方吗?或者如何自己找出来?我尝试了VisualVM,我可以看到Threads
数字下降,但无法找出原因: - (
答案 0 :(得分:0)
嗯,事实证明根本不涉及多线程。问题是某些连接没有建立,并且从某些点读取InputStream失败(我猜这与打开许多并发连接有关)。
一旦我使用了setConnectTimeout()和setReadTimeout(),问题就消失了。我还在3迭代循环中进行每个连接,因此在触发超时的情况下,连接将被重试2次。