通过最小分配的处理程序消息传递数组的副本?

时间:2011-06-21 16:29:25

标签: java android multithreading optimization

我正在后台线程上读取蓝牙数据流,并将该数据传递到UiThread,以便通过Message Handler进行处理和显示。可以找到有关该过程的更详细描述here

目前我正在将InputStream读取到byte[]并使用Handler.obtainMessage()来获取带有字节数组作为对象争论的消息。

我遇到了一个problem数据包会覆盖彼此,因为数组没有跨线程锁定,并且在UiThread可以处理之前在后台被覆盖。显而易见的解决方案是将数组复制到新数组并传递新对象。

问题是这在Android上非常昂贵,我将获得相当连续的数据流。有没有更好的方法将此数据传递给主UiThread? 也许通过同步字节数组或更高效的内存复制方式?

4 个答案:

答案 0 :(得分:5)

在Android中执行此操作的典型方法是拥有一个已分配对象池。上课:

class DataBuffer {
    DataBuffer next;
    byte[] data;
}

你可以像这样管理它们:

final Object mLock = new Object();
DataBuffer mPool;

DataBuffer obtain() {
    synchronized (mLock) {
        if (mPool != null) {
            DataBuffer res = mPool;
            mPool = res.next;
            return res;
        }
        return new DataBuffer();
    }
}

void recycle(DataBuffer buffer) {
    synchronized (mLock) {
        buffer.next = mPool;
        mPool = buffer;
    }
}

答案 1 :(得分:1)

数据进入与消耗的速度有多快?

为什么不分配第二个数组,一个用于读取一个用于写入,根据需要进行切换。

当流完成写入阵列1时,释放其互斥锁并等待阵列2变为可用。然后你可以通过你的处理程序将数组1传递给UI线程,这将获得该数组的锁定。通过像这样切换数组,您可以确保数据不会丢失,因为通过互斥来控制每个数据。

如果您的数据进入的速度快于读取数据,则可能会出现问题。 (蓝牙数据蒸汽是否可以阻止并等待?)

答案 2 :(得分:1)

听起来你想要的是你可以检查使用的字节数组池,并在完成时检入。实现可能看起来像

public class BytePool {
  private class PoolObject {
    public byte[] buffer = byte[1024];
    public boolean available = false;
  }

  ArrayList<PoolObject> pool = new ArrayList<PoolObject>();

  public synchronized byte[] checkOut() {
    boolean found = false;
    for (PoolObject obj : pool) {
      if (obj.available) {
        obj.available = false;
        return obj.buffer;
      }
    }
    PoolObject newObj = new PoolObject();
    pool.add(newObj);
    return newObj.buffer;
  }

  public synchronized void checkIn(byte[] finished) {
    for (PoolObject obj : pool) {
      if (obj.buffer == finished) {
        obj.available = true;
      }
    }
  }
}

免责声明:我实际上没有测试过甚至编译过这段代码,只是为了传达基本的想法。

有了这个,你希望在任何给定的时间分配最小数量的byte []对象。理想情况下,您还希望添加一些代码以减少池大小,如果由于某种原因它扩展了一堆,现在所需的池大小更小。

我个人认为,在明确是否需要微观优化之前,你可能会担心微观优化。 (或者您可能已经分析过您的应用程序并知道您需要它。)

更新:Hackbod的解决方案实际上比我建议的解决方案更有效,尽管它仍然可能因池中有太多对象而受到影响。

答案 3 :(得分:0)

不知道android,但通常将这些数据读入动态分配的缓冲区,在消息中发布其引用并立即分配一个新数据,为下一批数据做好准备。这消除了复制并确保两个线程始终在不同的数据上运行。

RGDS, 马丁