有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

目前,我正在将InputStream读入一个byte[],并使用Handler.obtainMessage()获取一条以字节数组作为对象参数的消息

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

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


共 (4) 个答案

  1. # 1 楼答案

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

    Rgds, 马丁

  2. # 2 楼答案

    在安卓系统中实现这一点的典型方式是拥有一个分配对象池。上这门课:

    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;
        }
    }
    
  3. # 3 楼答案

    这听起来像是你想要的字节数组池,你可以签出使用,并在完成后签入。一个实现可能看起来像

    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的解决方案实际上比我建议的更有效,尽管它仍然可能会受到池中对象太多的影响

  4. # 4 楼答案

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

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

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

    然而,如果数据的输入速度比读取速度快,则可能会出现问题。(蓝牙数据蒸汽能承受得起封锁和等待吗?)