【发布时间】:2015-07-15 07:13:25
【问题描述】:
我正在尝试在我的 Vaadin 应用程序中实现多线程刷新 UI。
此 UI 的一部分是基于容器的 dChart。构建dChart我遍历容器并通过它们的属性之一计数元素,如下所示:
Collection<?> itemIDS = container.getItemIds();
for (Object itemID : itemIDS) {
Property property = container.getContainerProperty(itemID, "status");
String status = (String) property.getValue();
if (countMap.containsKey(status)) {
countMap.put(status, countMap.get(status) + 1);
} else {
countMap.put(status, 1);
}
}
但是,如果容器有数千个元素,则需要 2-3 秒。
用户不能等待这么久来刷新用户界面。
我读到我可以构建我的 UI,然后在 dChart 完全构建后使用@Push Vaadin 注释刷新它。
所以我构建了这样的东西:
{
//class with @Push
void refreshPieDChart(GeneratedPropertyContainer container) {
new InitializerThread(ui, container).start();
}
class InitializerThread extends Thread {
private LogsUI parentUI;
private GeneratedPropertyContainer container;
InitializerThread(LogsUI ui, GeneratedPropertyContainer container) {
parentUI = ui;
this.container = container;
}
@Override
public void run() {
//building dChart etc etc... which takes over 2-3 seconds
// Init done, update the UI after doing locking
parentUI.access(new Runnable() {
@Override
public void run() {
chart.setDataSeries(dataSeries).show();
}
});
}
}
}
但是如果我刷新页面几次,它会产生关于SQLContainer的错误:
java.lang.IllegalStateException: A trasaction is already active!
因为经过几次刷新,我的多个线程使用同一个 SQLContainer 并行运行。
为了解决这个问题,我想停止除最后一个之外的所有工作刷新线程以消除并发问题。我该怎么做?也许其他解决方案?
编辑: 我已经尝试过这样的smth,但问题仍然存在,这是防止并发问题的正确方法吗?
{
private static final Object mutex = new Object();
//class with @Push
void refreshPieDChart(GeneratedPropertyContainer container) {
new InitializerThread(ui, container).start();
}
class InitializerThread extends Thread {
private LogsUI parentUI;
private GeneratedPropertyContainer container;
InitializerThread(LogsUI ui, GeneratedPropertyContainer container) {
parentUI = ui;
this.container = container;
}
@Override
public void run() {
//is it correct way to prevent concurrent problem?
synchronized(mutex){
//method to refresh/build chart which takes 2-3s.
}
// Init done, update the UI after doing locking
parentUI.access(new Runnable() {
@Override
public void run() {
chart.setDataSeries(dataSeries).show();
}
});
}
}
}
【问题讨论】:
-
您是否考虑过延迟加载您的数千个条目?
-
@tk12 这正是我现在正在做的事情,或者不是?我仅根据用户请求(刷新,输入我的 web 应用程序)构建 UI(图表)。但是当我想构建一个图表时,我需要立即获取所有数据(否则我的图表将过时)
-
所有数据都一次显示在屏幕上吗?这就是我所说的延迟加载。如果用户一次只能看到一部分数据,您可以在数据显示在屏幕上时延迟加载数据,从而提高加载性能。但是,如果您想一次使用 所有数据,那么我的建议可能不适合您的需求。
-
@tk12 如果我的图表正在计算 SQLContainer 中的元素,那么您就不能使用延迟加载,因为您需要计算每个元素,这意味着您无论如何都需要加载它。你是对的,延迟加载非常适合加载部分数据,例如:滚动表。但在这种特殊情况下,我需要获取所有数据。
-
@ilovkatie 我认为您应该在 SQL 中进行计数,然后它应该足够快。那你就不用多线程了。
标签: java multithreading user-interface vaadin