使用线程池退出线程的无限循环
我在使用多线程的代码中工作。相关代码的结构如下:使用线程池退出线程的无限循环
try {
ExecutorService threadExecutor = Executors.newFixedThreadPool(10);
while (resultSet.next()) {
name = resultSet.getString("hName");
MyRunnable worker = new Myrunnable(name);
threadExecutor.execute(worker);
Counter++;
}
//This never appears
System.out.println("End while with counter" + Counter);
threadExecutor.shutdown();
System.out.println("thread shutdown"); //this never appears
// Wait until all threads are finish
while (!threadExecutor.isTerminated()) {
threadExecutor.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("inside the thread termination loop."); //I have infinite loop
}
System.out.println("Finished all threads"); //never appears
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("END MAIN");
DBConnection.con.close();
运行函数肯定会结束。我的数据库中的姓氏执行所需的功能,并且其线程结束。
//The constructor
MyRunnable (String name) {
this.name=name;
}
public void run() {
myclass Obj=new myclass();
try {
Obj.myFunction(name);
} catch (Exception e) {
System.out.println("Got an Exception: "+e.getMessage());
}
System.out.println(" thread exiting" + this.name);
}
我的问题是我的程序正确执行的一切只是在最后一个线程,我看到了“线程退出”从DB的姓氏。但是threadexecutor从不关闭,程序进入无限循环。
编辑
这里是主要的,它可以提取数据库名称的代码。
try {
st = DBConnection.con.createStatement();
resultSet = st.executeQuery("select hName from schema1.table1 where checked=1 order by hName");
} catch (Exception e) {
System.out.println("DB Error: " + e.getMessage());
}
这里是发生了什么事我最好的猜测:
首先,我怀疑,这两个意见:
//This never appears
System.out.println("End while with counter" + Counter);
threadExecutor.shutdown();
System.out.println("thread shutdown"); //this never appears
是不正确的。我强烈怀疑,实际上你确实得到了这些消息,但他们混入了你的其他消息(如“线程退出”消息),所以你想念他们。
其次,我怀疑有时候,Obj.myfunction(name)
挂起。如果Obj.myfunction
涉及回写数据库,这很可能会发生 - 大多数情况下它都能正常工作,但是偶尔会发生(并且更可能使用更多行),您会遇到数据库死锁。所以,事实上,你没有得到的“线程退出”消息,每个名称,但找到列表中间的一个或两个不会给你这个消息将是困难的。
要确定是否属于这种情况,我会在坐在无限循环中时生成Java程序的线程转储。在Unix/Mac上,通过打开另一个窗口并执行kill -3 PID
来完成此操作,其中PID
是您的java进程的进程ID。在Windows中,我认为您需要使用的组合键是Ctrl-Break。在胎面转储中,查看线程池的工作线程是否卡在Obj.myfunction
的调用中。
数据库死锁的一个可能的来源是,在程序结束时关闭数据库连接本身之前,您不要关闭ResultSet
。我想你的while
循环结束之后添加一个调用
resultSet.close();
,你打印出来之前你对"End while with counter"
消息。如果即使在添加该语句后仍然发生数据库死锁,那么您将不得不问一个关于该功能myfunction
正在做什么的不同问题。
对于数据库,我同步查询: Query =“insert into table values(default,?,?)'和准备好的语句:'preparedStmt = DBConnection.con.prepareStatement(Query);'但是我不同步插入并执行:'preparedStmt.setString(1,token);''和'preparedStmt.executeUpdate();'。你是否看到这个问题? – 2012-07-16 19:33:00
我不认为你明白什么可能导致数据库锁定 - 但如果你在工作线程中调用的是写入*相同的表*,那么你最初选择的是_really_,只要while循环结束就想关闭你的'resultSet'。 – 2012-07-17 14:39:13
No.我不想写在同一张桌子上,他们是两张不同的表格,我之前的问题是一般性的,因为我从第一个位置对此有所怀疑,我会尽量关闭结果集并尽快更新 – 2012-07-17 16:14:20
您最后的评论更有意义:当您运行executor.execute(..)
时,它并不意味着该线程将立即运行,即使它立即启动,它也不会打印“线程退出”消息,直到它完成。同时,主线程继续,并将:
- 打印
System.out.println("End while with counter" + Counter);
- 运行的
threadExecutor.shutdown();
应返回几乎立即 - 打印
System.out.println("thread shutdown");
几乎立即太。
换句话说,如果你的线程正在做什么需要一点时间,那么在任何线程完成任务之前,这两行将被打印出来。
现在,如果你的程序不退出,这是最有可能的,因为已经评论的原因是什么Obj.myFunction(name)
是干什么的, - 如果调用从来没有出于某种原因结束,你的结果集比你的线程池的大小更多的记录,while (!threadExecutor.isTerminated())
循环将永远不会结束。
那么,这是否意味着,我必须将线程池的大小设置为记录编号?例如:如果我有1000条记录,我应该将我的池大小设置为1000? – 2012-07-16 14:18:57
不,这意味着您必须了解阻止线程退出并修复它的原因。丹尼尔马丁在他的回答中提出了一些想法。没有更多信息,我们无法真正帮助更多。再一次,如果你设法创建一个能够再现行为的SSCCE,那么找出问题的原因将会容易得多。 – assylias 2012-07-16 14:22:11
该函数执行SSL握手。程序在单线程模式下不会遇到问题。我确定该功能结束。现在,请再提一个问题。如果我想在打印'System.out.println(“在线程终止循环内部”)的循环中输出'name'的值,''。我怎样才能做到这一点?当我打印变量'worker.name'时,我认为这个特定的线程在'循环内部'时给了'name'的值,但我总是从DB中检索到最后一个'name'。 – 2012-07-18 23:40:00
你说这个消息'结束while计数器结束'永远不会出现。所以你的程序永远不会退出while循环。然后它听起来不像一个'ExecutorService'相关的问题。 – 2012-07-14 09:14:34
请注意,如果从数据库读取少量记录,则线程结束并且程序终止。但是当数字增加时,程序永远不会终止(或者至少长时间停留在循环中(+5分钟),直到我手动终止它) – 2012-07-14 09:15:16
然后它可能与'Obj.myFunction(name)'是什么有关如果它永远不会结束,并且结果集有超过10条记录(池的大小),则while循环永远不会结束。 – assylias 2012-07-14 09:16:36