Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Vaadin中的多线程刷新UI_Java_Multithreading_User Interface_Vaadin - Fatal编程技术网

Java Vaadin中的多线程刷新UI

Java Vaadin中的多线程刷新UI,java,multithreading,user-interface,vaadin,Java,Multithreading,User Interface,Vaadin,我正在尝试在我的Vaadin应用程序中实现一个多线程刷新UI 此UI的一部分是基于容器的dChart。要构建dChartIm遍历容器并按其属性之一计算元素,如下所示: Collection<?> itemIDS = container.getItemIds(); for (Object itemID : itemIDS) { Property property = container.getContainerProperty(

我正在尝试在我的Vaadin应用程序中实现一个多线程刷新UI

此UI的一部分是基于容器的
dChart
。要构建
dChart
Im遍历容器并按其属性之一计算元素,如下所示:

        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);
            }
        }
{
//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!
countContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
因为在几次刷新之后,我的多个线程使用同一个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();
            }
        });
    }
  }
}
这就是我所做的:

给我指出了一个非常明显的想法:用SQL进行计数。正如我所说,我正在考虑这个问题,但这意味着我需要为每个可能的过滤器组合准备SQL。这是一个相当复杂的问题,看起来不太好

但这让我意识到,如果我在我的表中使用带有过滤器的SQLContainer,我也可以在计数中使用同样的方法。我只需要用自己的
FreeformQuery
freeformstatementdegate
创建第二个
SQLContainer

如果我将创建以上所有内容,我可以将相同的过滤器添加到两个容器中,但是我现在不需要计算元素,因为第二个容器为我保存值。听起来很复杂,但看看我的代码:

FreeformQuery myQuery = new MyFreeformQuery(pool);
FreeformQuery countQuery = new CountMyFreeformQuery(pool);

SQLContainer myContainer = new SQLContainer(myQuery);  //here i hold my all records as in a Question
SQLContainer countContainer = new SQLContainer(countQuery);  //here i hold computed count(*) and status
MyFreeformQuery.java看起来像:

class ProcessFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING = "SELECT request_date, status, id_foo FROM foo";
private static final String COUNT_STRING = "SELECT COUNT(*) FROM foo";
private static final String PK_COLUMN_NAME = "id_foo";

MyFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING, connectionPool, PK_COLUMN_NAME);
    setDelegate(new AbstractFreeformStatementDelegate() {

        protected String getPkColumnName() {
            return PK_COLUMN_NAME;
        }

        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getCountString() {
            return COUNT_STRING;
        }
    });
}
public class CountFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING_GROUP = "SELECT status, count(*) as num FROM foo GROUP BY status";
private static final String QUERY_STRING = "SELECT status, count(*) as num FROM foo";
private static final String GROUP_BY = "foo.status";

public CountFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING_GROUP, connectionPool);
    setDelegate(new CountAbstractFreeformStatementDelegate() {
        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getGroupBy(){
            return GROUP_BY;
        }

    });
}
}
最重要的CountFreeformQuery.java如下所示:

class ProcessFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING = "SELECT request_date, status, id_foo FROM foo";
private static final String COUNT_STRING = "SELECT COUNT(*) FROM foo";
private static final String PK_COLUMN_NAME = "id_foo";

MyFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING, connectionPool, PK_COLUMN_NAME);
    setDelegate(new AbstractFreeformStatementDelegate() {

        protected String getPkColumnName() {
            return PK_COLUMN_NAME;
        }

        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getCountString() {
            return COUNT_STRING;
        }
    });
}
public class CountFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING_GROUP = "SELECT status, count(*) as num FROM foo GROUP BY status";
private static final String QUERY_STRING = "SELECT status, count(*) as num FROM foo";
private static final String GROUP_BY = "foo.status";

public CountFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING_GROUP, connectionPool);
    setDelegate(new CountAbstractFreeformStatementDelegate() {
        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getGroupBy(){
            return GROUP_BY;
        }

    });
}
}
现在,如果我想在smth之后刷新
dChart
,如下所示:

myContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
    Map<String, Long> countMap = new HashMap<String, Long>();
    Collection<?> itemIDS = container.getItemIds();
    for (Object itemID : itemIDS) {
        Property statusProperty = container.getContainerProperty(itemID, "status");
        Property numProperty = container.getContainerProperty(itemID, "num");
        countMap.put((String) statusProperty.getValue(), (Long) numProperty.getValue());
    }
我只是对countContainer做了同样的操作:

java.lang.IllegalStateException: A trasaction is already active!
countContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
并将其传递给不需要计算元素的方法,只需将所有容器添加到map,然后添加到dChart,如下所示:

myContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
    Map<String, Long> countMap = new HashMap<String, Long>();
    Collection<?> itemIDS = container.getItemIds();
    for (Object itemID : itemIDS) {
        Property statusProperty = container.getContainerProperty(itemID, "status");
        Property numProperty = container.getContainerProperty(itemID, "num");
        countMap.put((String) statusProperty.getValue(), (Long) numProperty.getValue());
    }
Map countMap=newhashmap();
Collection itemIDS=container.getItemIds();
for(对象itemID:itemIDS){
Property statusProperty=container.getContainerProperty(itemID,“status”);
属性numProperty=container.getContainerProperty(itemID,“num”);
countMap.put((字符串)statusProperty.getValue(),(长)numProperty.getValue();
}
现在我已经统计了
status
myContainer中元素的数量,不需要多线程或编写大量sql

谢谢大家的建议。

我就是这么做的:

给我指出了一个非常明显的想法:用SQL进行计数。正如我所说,我正在考虑这个问题,但这意味着我需要为每个可能的过滤器组合准备SQL。这是一个相当复杂的问题,看起来不太好

但这让我意识到,如果我在我的表中使用带有过滤器的SQLContainer,我也可以在计数中使用同样的方法。我只需要用自己的
FreeformQuery
freeformstatementdegate
创建第二个
SQLContainer

如果我将创建以上所有内容,我可以将相同的过滤器添加到两个容器中,但是我现在不需要计算元素,因为第二个容器为我保存值。听起来很复杂,但看看我的代码:

FreeformQuery myQuery = new MyFreeformQuery(pool);
FreeformQuery countQuery = new CountMyFreeformQuery(pool);

SQLContainer myContainer = new SQLContainer(myQuery);  //here i hold my all records as in a Question
SQLContainer countContainer = new SQLContainer(countQuery);  //here i hold computed count(*) and status
MyFreeformQuery.java看起来像:

class ProcessFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING = "SELECT request_date, status, id_foo FROM foo";
private static final String COUNT_STRING = "SELECT COUNT(*) FROM foo";
private static final String PK_COLUMN_NAME = "id_foo";

MyFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING, connectionPool, PK_COLUMN_NAME);
    setDelegate(new AbstractFreeformStatementDelegate() {

        protected String getPkColumnName() {
            return PK_COLUMN_NAME;
        }

        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getCountString() {
            return COUNT_STRING;
        }
    });
}
public class CountFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING_GROUP = "SELECT status, count(*) as num FROM foo GROUP BY status";
private static final String QUERY_STRING = "SELECT status, count(*) as num FROM foo";
private static final String GROUP_BY = "foo.status";

public CountFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING_GROUP, connectionPool);
    setDelegate(new CountAbstractFreeformStatementDelegate() {
        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getGroupBy(){
            return GROUP_BY;
        }

    });
}
}
最重要的CountFreeformQuery.java如下所示:

class ProcessFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING = "SELECT request_date, status, id_foo FROM foo";
private static final String COUNT_STRING = "SELECT COUNT(*) FROM foo";
private static final String PK_COLUMN_NAME = "id_foo";

MyFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING, connectionPool, PK_COLUMN_NAME);
    setDelegate(new AbstractFreeformStatementDelegate() {

        protected String getPkColumnName() {
            return PK_COLUMN_NAME;
        }

        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getCountString() {
            return COUNT_STRING;
        }
    });
}
public class CountFreeformQuery extends FreeformQuery {

private static final String QUERY_STRING_GROUP = "SELECT status, count(*) as num FROM foo GROUP BY status";
private static final String QUERY_STRING = "SELECT status, count(*) as num FROM foo";
private static final String GROUP_BY = "foo.status";

public CountFreeformQuery(JDBCConnectionPool connectionPool) {
    super(QUERY_STRING_GROUP, connectionPool);
    setDelegate(new CountAbstractFreeformStatementDelegate() {
        protected String getQueryString() {
            return QUERY_STRING;
        }

        protected String getGroupBy(){
            return GROUP_BY;
        }

    });
}
}
现在,如果我想在smth之后刷新
dChart
,如下所示:

myContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
    Map<String, Long> countMap = new HashMap<String, Long>();
    Collection<?> itemIDS = container.getItemIds();
    for (Object itemID : itemIDS) {
        Property statusProperty = container.getContainerProperty(itemID, "status");
        Property numProperty = container.getContainerProperty(itemID, "num");
        countMap.put((String) statusProperty.getValue(), (Long) numProperty.getValue());
    }
我只是对countContainer做了同样的操作:

java.lang.IllegalStateException: A trasaction is already active!
countContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
并将其传递给不需要计算元素的方法,只需将所有容器添加到map,然后添加到dChart,如下所示:

myContainer.addContainerFilter(new Between(DATE_PROPERTY, getTimestamp(currentDate), getOneDayAfter(currentDate)));
    Map<String, Long> countMap = new HashMap<String, Long>();
    Collection<?> itemIDS = container.getItemIds();
    for (Object itemID : itemIDS) {
        Property statusProperty = container.getContainerProperty(itemID, "status");
        Property numProperty = container.getContainerProperty(itemID, "num");
        countMap.put((String) statusProperty.getValue(), (Long) numProperty.getValue());
    }
Map countMap=newhashmap();
Collection itemIDS=container.getItemIds();
for(对象itemID:itemIDS){
Property statusProperty=container.getContainerProperty(itemID,“status”);
属性numProperty=container.getContainerProperty(itemID,“num”);
countMap.put((字符串)statusProperty.getValue(),(长)numProperty.getValue();
}
现在我已经统计了
status
myContainer中元素的数量,不需要多线程或编写大量sql


谢谢大家的建议。

你有没有考虑为你的数以千计的条目加载懒惰?@ TK12这就是我现在正在做的,不是吗?仅在用户请求时(刷新,输入我的webapp),Im生成UI(图表)。但是,当我想建立一个图表时,我需要在一瞬间获得所有数据(否则我的图表将过时),所有数据是否立即显示在屏幕上?这就是我所说的延迟加载。如果用户一次只看到一部分数据,则可以在数据显示在屏幕上时延迟加载数据,从而提高加载性能。但是如果您想一次使用所有数据,那么我的建议可能不适合您的需要。@tk12如果我的图表正在计算SQLContainer中的元素,您就不能使用延迟加载,因为您需要计算每个元素,这意味着您无论如何都需要加载它。您是对的,延迟加载非常适合加载部分数据,例如:滚动表。但是在这种特殊情况下,我需要获取所有数据。@ilovkatie我认为应该用SQL进行计数,然后应该足够快。那么你没有多线程。你有没有考虑到你的成千上万条条目的懒惰加载?@ TK12这就是我现在正在做的,不是吗?仅在用户请求时(刷新,输入我的webapp),Im生成UI(图表)。但是,当我想建立一个图表时,我需要在一瞬间获得所有数据(否则我的图表将过时),所有数据是否立即显示在屏幕上?这就是我所说的延迟加载。如果用户一次只看到一部分数据,则可以在数据显示在屏幕上时延迟加载数据,从而提高加载性能。但是如果您想一次使用所有数据,那么我的建议可能不适合您的需要。@tk12如果我的图表正在计算SQLContainer中的元素,您就不能使用lazy lo