【问题标题】:J2ME/Java: Referencing StringBuffer through ThreadsJ2ME/Java:通过线程引用 StringBuffer
【发布时间】:2010-03-01 04:19:22
【问题描述】:

这个问题可能很长,但我想提供很多信息。

概述:我正在为 Blackberry 创建一个 Stock Quotes Ticker 应用程序。但我的 StringBuffer 包含单个 Stock 信息时出现问题。

进程:我的应用通过 SocketConnection 连接到我们的服务器。服务器发出一组格式化的字符串,其中包含最新的股票交易。因此,每当发生新交易时,服务器都会发送该交易的单个股票报价。通过 InputStream,我能够读取该信息并将每个字符放在线程引用的 StringBuffer 中。通过基于 char3 的解析,我能够确定一组股票报价/信息。

char1 - 分隔数据 char3 - 表示股票报价/信息的结束

我们的服务器发出的股票报价格式示例: stock_quote_name(char 1)some_data(char1)some_data(char1)(char3)

然后,我的应用程序会解析该股票报价以比较某些数据,并将其格式化为在屏幕上显示时的样子。当交易逐渐(缓慢)发生时,该应用程序可以完美运行。不过..

问题:当交易发生得太快且几乎同时发生时,我的应用程序无法有效处理发送的信息。 StringBuffer 的内容与下一笔交易相结合。含义 一个 StringBuffer 中的两个股票信息。

字段应该是: Stock_quote_name some_data some_data

正在发生的事情示例: Stock_quote_name some_data some_dataStock_quote_name some_data some_data

这是我这部分的代码:

while (-1 != (data = is.read()))
                {
                       sb.append((char)data);
                       while(3 != (data = is.read()))
                       {
                           sb.append((char)data);
                       }
                       UiApplication.getUiApplication().invokeLater(new Runnable()
                       {
                           public void run()
                           {
                               try
                               {
                                   synchronized(UiApplication.getEventLock())
                                   {
                                       SetStringBuffer(sb);
                                       DisplayStringBuffer();
                                       RefreshStringBuffer();
                                   }
                               } catch (Exception e)
                               {
                                   System.out.println("Error in setting stringbuffer: " + e.toString());
                               }
                           }
                       });
                }

public synchronized void DisplayStringBuffer()
{
    try
    {
        //parse sb - string buffer
        ......
    }
    catch(Exception ex)
    {
        System.out.println("error in DisplayStringBuffer(): " + ex.toString());
    }
}
public synchronized void SetStringBuffer(StringBuffer dataBuffer)
{
    this.sb =dataBuffer;
    System.out.println(sb);
}
public synchronized void RefreshStringBuffer()
{
    this.sb.delete(0, this.sb.length());
}

据我所见,当交易发生得非常快时,当我尝试放入新数据时,StringBuffer 不会立即刷新,并且仍然具有先前交易的内容。

我的问题是: 你们对我如何将数据放入 StringBuffer 有什么建议,而不会将下一个信息附加到第一个内容中

【问题讨论】:

    标签: blackberry multithreading java-me inputstream stringbuffer


    【解决方案1】:

    您读取数据的部分是同步的,但您将数据附加到缓冲区的部分不是。如果您每次都重用相同的 StringBuffer,您将遇到竞争条件。

    【讨论】:

    • 那么你建议我在每次 While 循环迭代时创建一个新的 StringBuffer 吗?
    【解决方案2】:

    好吧,既然您正在使用 invokeLater 来设置/显示/清除您的 StringBuffer,那么您是对的,没有什么可以阻止您返回到下一个 read() 调用并在您能够显示之前修改该 StringBuffer它。

    显然,您不是从事件线程的输入流中读取数据,因此为了更新 UI,您需要使用 invokeLater 或在事件锁上同步,但您正在同时执行这两种操作。

    如果您想使用invokeLater,那么您需要确保当您的事件线程尝试在UI 中显示数据时,不要将输入流读取器线程附加到您的StringBuffer。因此,您可能会考虑为每个 Runnable 创建一个新的 StringBuffer。

    如果您想在事件锁上进行同步,这样的事情可能会起作用(这可能会更好,因为它可以避免通过创建新的 Runnables / StringBuffers 创建不必要的垃圾)。

    while (-1 != (data = is.read()))
                {
                       sb.append((char)data);
                       while(3 != (data = is.read()))
                       {
                           sb.append((char)data);
                       }
    
                       synchronized(UiApplication.getEventLock())
                       {
                           SetStringBuffer(sb);
                           DisplayStringBuffer();
                           RefreshStringBuffer();
                       } 
                }
    

    【讨论】:

      【解决方案3】:

      您不能为每个股票报价重复使用相同的 StringBuffer,因为您在 UI 线程完成显示最后一个股票报价之前正在阅读下一个股票报价。请记住,您正在一个线程上写入 StringBuffer,并在另一个线程上读取 StringBuffer。无法保证 UI 线程(读取线程)在循环迭代并开始将下一个股票报价附加到 StringBuffer 之前调用了 RefreshStringBuffer()。

      改为使用字符串集合。

      java.util.queue<String> q = new java.util.concurrent.ConcurrentLinkedQueue<String>();
      

      然后在您完成将报价放入某人后执行q.add(sb.toString());

      显示引号

      public void DisplayStockQuote() {
          while(!q.isEmpty()) {
              String s = q.poll();
      
              // display s
              try
              {
                  //parse s - string containing stock quote
                  ......
              }
              catch(Exception ex)
              {
                  System.out.println("error in DisplayStringBuffer(): " + ex.toString());
              }
      
          }
      }
      

      从您的 UI 线程调用该方法,而不是

      SetStringBuffer(sb);
      DisplayStringBuffer();
      RefreshStringBuffer();
      

      我建议您尽量避免使用额外的线程并采用 Bradley 的解决方案。但是如果你真的想要有两个线程,这样的事情就可以了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-05
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 2020-05-03
        • 1970-01-01
        • 2011-04-14
        • 2013-06-17
        相关资源
        最近更新 更多