我使用单独的线程来处理文件的处理。主线程保存表以使用listView显示给用户,并使用AjaxSelfUpdatingTimer每秒刷新列表。
问题是,在我的CSV文件中处理了大约100行后,我一直收到no requestCyle异常:
Exception in thread "Thread-12" org.apache.wicket.WicketRuntimeException: No RequestCycle is currently set!
at org.apache.wicket.Component.getRequest(Component.java:1804)
at org.apache.wicket.markup.html.WebPage.dirty(WebPage.java:318)
at org.apache.wicket.Page.dirty(Page.java:249)
at org.apache.wicket.Page.componentStateChanging(Page.java:926)
at org.apache.wicket.Component.addStateChange(Component.java:3528)
at org.apache.wicket.Component.error(Component.java:1225)
at com.wicket.BulkLoadPage$BatchLoaderProcessingThread.processLine(BulkLoadPage.java:806)
at com.wicket.BulkLoadPage$BatchLoaderProcessingThread.run(BulkLoadPage.java:674)
at java.lang.Thread.run(Thread.java:662)
这些是线程调用的可运行类:
class BatchLoaderProcessingThread implements Runnable
{
@Override
public void run()
{
processLine();
loaderFinished();
}
public void cancelThread()
{
cancelLoaderThread = true;
}
}
class BatchDeleteProcessingThread implements Runnable
{
@Override
public void run()
{
processLine();
deleterFinished();
}
public void cancelThread()
{
cancelDeleterThread = true;
}
}
我不明白为什么requestCycle会变为null ..如何防止这种情况发生?
编辑:
注释掉反馈消息确实排除了requestRecycle错误,我收到此错误:
java.io.IOException: Read error
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:220)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.read1(BufferedReader.java:185)
at java.io.BufferedReader.read(BufferedReader.java:261)
at java.io.BufferedReader.fill(BufferedReader.java:136)
Dec 30 13:14:31 ERROR BulkLoadPage-java.io.IOException: Read error
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at au.com.bytecode.opencsv.CSVReader.getNextLine(CSVReader.java:266)
at au.com.bytecode.opencsv.CSVReader.readNext(CSVReader.java:233)
at com..wicket.BulkLoadPage.processLine(BulkLoadPage.java:547)
at com..wicket.BulkLoadPage.access$0(BulkLoadPage.java:532)
at
com..wicket.BulkLoadPage$BatchLoaderProcessingThread.run(BulkLoadPage.java:1294)
at java.lang.Thread.run(Thread.java:662)
此错误仅在较大的文件中发生。 csv中的所有行都是重复的,只能模仿一个大文件..所以所有行都是相同的,不应该直接从文件引起错误。还有其他我应该寻找的东西会导致这个错误使用另一个线程吗?
答案 0 :(得分:1)
RequestCycle是一个线程本地单例。如果你在另一个线程中运行一个进程,那真的意味着你的新线程中不存在RequestCycle单例。
以下示例放在https://repo.twinstone.org/projects/WISTF/repos/wicket-examples-1.4/browse
上这个想法是关于保持对当前RequestCycle的引用,你不能调用RequestCycle.get(),因为线程本地单例在任何其他线程中都不存在。此CustomRequestCycle实现一直等到新线程通知其完成。循环计数器只是一个保护,如果WaitingRunnable停止工作/冻结,不冻结主线程。
测试结果:
检查您的日志案例1 ,单独的线程即将完成, RequestCycle不等待分离
http://localhost:8080/wicket-examples14/wait?millis=10
DEBUG - CustomRequestCycle - Waiting until notify: 0
INFO - WaitingRunnableNotifier - Separate thread waiting finished cz.wicketstuff.enteam.wicket.examples14.request.ThreadWaitingPage
INFO - CustomRequestCycle - Notifier returned: Successfully finished
检查您的日志案例2 ,单独的帖子正在及时完成, RequestCycle必须等待分离
http://localhost:8080/wicket-examples14/wait?millis=3000
DEBUG - CustomRequestCycle - Waiting until notify: 0
DEBUG - CustomRequestCycle - Waiting until notify: 1
DEBUG - CustomRequestCycle - Waiting until notify: 2
INFO - WaitingRunnableNotifier - Separate thread waiting finished cz.wicketstuff.enteam.wicket.examples14.request.ThreadWaitingPage
INFO - CustomRequestCycle - Notifier returned: Successfully finished
检查您的日志案例3 ,单独的帖子正在按时完成, RequestCycle已经分离
http://localhost:8080/wicket-examples14/wait?millis=10000
DEBUG - CustomRequestCycle - Waiting until notify: 0
DEBUG - CustomRequestCycle - Waiting until notify: 1
DEBUG - CustomRequestCycle - Waiting until notify: 2
DEBUG - CustomRequestCycle - Waiting until notify: 3
DEBUG - CustomRequestCycle - Waiting until notify: 4
DEBUG - CustomRequestCycle - Waiting until notify: 5
DEBUG - CustomRequestCycle - Waiting until notify: 6
DEBUG - CustomRequestCycle - Waiting until notify: 7
INFO - CustomRequestCycle - Notifier returned: null
INFO - WaitingRunnableNotifier - Separate thread waiting finished cz.wicketstuff.enteam.wicket.examples14.request.ThreadWaitingPage
<强>来源:强>
<强> WicketApplication 强>
@Override
public RequestCycle newRequestCycle(Request request, Response response) {
return new CustomRequestCycle(this, (WebRequest)request, (WebResponse)response);
}
<强> CustomRequestCycle 强>
public class CustomRequestCycle extends WebRequestCycle implements INotifier<String> {
private static final Logger log = LoggerFactory.getLogger(CustomRequestCycle.class);
private long sleepTime = 1000L;
private long maxLoops = 8;
private boolean canDetach = true;
private String notifierResult;
public CustomRequestCycle(WicketApplication application, WebRequest request,
Response response) {
super(application, request, response);
}
public void notifyAny(String payload) {
notifierResult = payload;
canDetach = true;
}
@Override
public void detach() {
long counter = 0;
while(!canDetach && maxLoops > counter) {
log.debug("Waiting until notify: " + counter);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// do nothing
}
counter++;
}
log.info("Notifier returned: " + notifierResult);
super.detach();
}
public static CustomRequestCycle get() {
return (CustomRequestCycle)RequestCycle.get();
}
/**
* @return the canDetach
*/
public boolean isCanDetach() {
return canDetach;
}
/**
* @param canDetach the canDetach to set
*/
public void setCanDetach(boolean canDetach) {
this.canDetach = canDetach;
}
}
<强> WaitingRunnableNotifier 强>
public class WaitingRunnableNotifier implements Runnable {
private static final Logger log = LoggerFactory.getLogger(WaitingRunnableNotifier.class);
private final long waitTime;
private RequestCycle requestCycle;
private INotifier<String> notifier;
public WaitingRunnableNotifier(RequestCycle requestCycle, long waitTime, INotifier<String> notifier) {
super();
this.notifier = notifier;
this.requestCycle = requestCycle;
this.waitTime = waitTime;
}
public void run() {
String message = null;
try {
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
}
log.info("Separate thread waiting finished " + requestCycle.getResponsePageClass().getCanonicalName());
message = "Successfully finished";
} catch (Exception e) {
log.error("Exception during WaitingRunnableNotifier.run()", e);
message = "Exception: " + e.getMessage();
} finally {
notifier.notifyAny(message);
clean();
}
}
/**
* Clean object references
*/
private void clean() {
requestCycle = null;
notifier = null;
}
}
ThreadWaitingPage 是一个参数为“millis”的页面。在那里你可以调用另一个线程并等待它完成。
public class ThreadWaitingPage extends WebPage {
private static final long serialVersionUID = 1L;
private final long millis;
public ThreadWaitingPage(final PageParameters parameters) {
super(parameters);
millis = parameters.getLong("millis");
add(new Label("millis", String.valueOf(millis)));
}
@Override
protected void onInitialize() {
super.onInitialize();
CustomRequestCycle requestCycle = CustomRequestCycle.get();
requestCycle.setCanDetach(false);
new Thread(new WaitingRunnableNotifier(requestCycle, millis, requestCycle)).start();
}
}
答案 1 :(得分:1)
理想情况下,您不应该创建自己的线程,应该让容器为您完成所有这些操作。当然,这意味着您不能让请求之间在后台运行批量进程。
我之前做过类似的事情(违反我刚刚提到的规则!),最简单的方法是让Wicket脱离你自己的线程。例如,如果您的线程填充了List,并且您的ajax计时器回调从列表中提取记录并将它们添加到列表视图中。
列表视图的问题是您必须将父组件添加到ajax请求目标,这意味着整个列表视图将在ajax响应中发回,而不仅仅是您添加的新条目,而是所有旧的,这将破坏逐步加载它们的点。
作为唯一的CSV文件,您可能更好地使用数据表,并编写数据提供程序以打开文件并只读取该请求的记录,这应该更简单。
答案 2 :(得分:1)
我暂时修复了这个问题,首先将行加载到主线程中的字符串ArrayList中,然后从线程内的该列表中读取..
我真的没有看到任何延迟问题,所以这可能被认为是一个不错的选择吗?如果不是,请让我知道,否则希望这有助于其他人在某一天与此斗争。
我也在这里发布了我的问题: http://apache-wicket.1842946.n4.nabble.com/MultiThreading-issues-with-Wicket-td4663325.html#a4663389
并获得了一些很好的资源链接以供审核:
wicket中的多线程:
http://javathoughts.capesugarbird.com/2008/04/spawning-thread-for-lengthy-operation.html
RequestCycle: http://wicket.apache.org/guide/guide/chapter8.html