Java Android位图多线程处理-不是线程安全的?

Java Android位图多线程处理-不是线程安全的?,java,android,multithreading,image-processing,thread-safety,Java,Android,Multithreading,Image Processing,Thread Safety,我想在我的Android应用程序中处理位图-位图可能很大,所以我使用多线程来执行更快的操作。以下是我的代码(Runnable child的一部分): @覆盖 公开募捐{ int imageHeight=filter.getBitmap().getHeight(); int start=threadNumber*imageHeight/threadCount; int stop=(螺纹编号+1)*图像高度/螺纹计数; 对于(int j=开始;j

我想在我的Android应用程序中处理位图-位图可能很大,所以我使用多线程来执行更快的操作。以下是我的代码(Runnable child的一部分):

@覆盖
公开募捐{
int imageHeight=filter.getBitmap().getHeight();
int start=threadNumber*imageHeight/threadCount;
int stop=(螺纹编号+1)*图像高度/螺纹计数;
对于(int j=开始;j<停止;j++){
过滤线(j);
}
}
//...
受保护的void进程线(int lineNumber)
{
int width=bitmap.getWidth();
整数像素[]=新整数[宽度];
getPixels(像素,0,宽度,0,行号,宽度,1);
对于(int i=0;i
当我只使用池中的一个线程时,一切正常。不幸的是,当我使用的线程数等于处理器的内核数(在我的设备中为4)时,结果如下(对于灰度过滤器):

有时看起来:

  • bitmap.getPixels(…)不工作,因为输出中有黑线
  • bitmap.setPixels(…)不起作用,因为输出中有未更改的行

我说得对吗?这些函数是线程不安全的吗?如何执行多线程位图过滤以实现快速和线程安全?

Android中的2D图像处理由Skia库提供,Chrome也使用该库

很难找到一个明确的答案。“Skia不是线程安全的,尽管SkBitmap[被位图使用]是线程安全的……”我不知道该怎么想。我仔细阅读了一堆难以理解的JNI/C++代码,这是我能提供的最好的代码(这似乎比任何其他人都能做到):

我认为应该对整个位图调用
bitmap.getPixels()
。然后将生成的数组分割并执行线程处理。完成所有线程后,重新组装结果并调用
bitmap.setPixels()


它看起来像是
bitmap.getPixels()
bitmap.setPixels()
应该只不过是
memcpy()
s,但是在引擎盖下还有很多事情在进行,包括引用计数、图像缓存、颜色空间转换、预乘法,谁知道还有什么。将
Bitmap
方法从并行处理中移除应该可以避免麻烦。

这是我的最终答案。)删除我以前的解决方案。我已尝试使用
bitmap.getPixels()
解决方案,但也无法正常工作-存在未处理图像的碎片。不幸的是,我用这个恢复了更改。也许以后我会再次编写此代码并显示输出。当您这样做时,请发布执行线程的代码。啦啦老师,用
getPixels
解决整个图像效果很好,显然我第一次犯了一个错误。这种方法的缺点是内存消耗大。在没有任何拷贝的情况下“就地”过滤是完美的,但使用“getPixel”和“setPixel”显然是个坏主意,而且速度非常慢。除了使用安卓NDK,还有什么更好的解决方案吗?我认为NDK可能是一个不错的选择。您可以寻找第三方2D图像处理库,但仍然需要将像素复制到位图中,以便用户可以看到图像。唉。
@Override
public void run() {
    int imageHeight = filter.getBitmap().getHeight();
    int start = threadNumber * imageHeight / threadCount;
    int stop = (threadNumber + 1) * imageHeight / threadCount;
    for (int j = start; j < stop; j++) {
        filter.processLine(j);
    }
}
//...
protected void processLine(int lineNumber)
{
    int width = bitmap.getWidth();
    int pixels[] = new int[width];
    bitmap.getPixels(pixels, 0, width, 0, lineNumber, width, 1);
    for (int i = 0; i < width; i++) {
        pixels[i] = processPixel(pixels[i]);
    }
    bitmap.setPixels(pixels, 0, width, 0, lineNumber, width, 1);
}