Add multi-thread support for image decoding
This commit is contained in:
1 parent
9a0ba6f676
commit
0a472d28b5
1 file changed
+47
-21
@@ -107,6 +107,8 @@ public final class SpiderQueen implements Runnable {
|
||||
public static final int STATE_FINISHED = 2;
|
||||
public static final int STATE_FAILED = 3;
|
||||
|
||||
public static final int DECODE_THREAD_NUM = 1;
|
||||
|
||||
public static final String SPIDER_INFO_FILENAME = ".ehviewer";
|
||||
|
||||
private static final String[] URL_509_SUFFIX_ARRAY = {
|
||||
@@ -135,10 +137,9 @@ public final class SpiderQueen implements Runnable {
|
||||
private volatile Thread mQueenThread;
|
||||
private final Object mQueenLock = new Object();
|
||||
|
||||
@Nullable
|
||||
private Thread mDecoderThread;
|
||||
private final Thread[] mDecodeThreadArray = new Thread[DECODE_THREAD_NUM];
|
||||
private final int[] mDecodeIndexArray = new int[DECODE_THREAD_NUM];
|
||||
private final Stack<Integer> mDecodeRequestStack = new Stack<>();
|
||||
private final AtomicInteger mDecodingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX);
|
||||
|
||||
private final Object mWorkerLock = new Object();
|
||||
private ThreadPoolExecutor mWorkerPoolExecutor;
|
||||
@@ -182,6 +183,10 @@ public final class SpiderQueen implements Runnable {
|
||||
mWorkerMaxCount = MathUtils.clamp(Settings.getMultiThreadDownload(), 1, 10);
|
||||
mPreloadNumber = MathUtils.clamp(Settings.getPreloadImage(), 0, 100);
|
||||
|
||||
for (int i = 0; i < DECODE_THREAD_NUM; i++) {
|
||||
mDecodeIndexArray[i] = GalleryPageView.INVALID_INDEX;
|
||||
}
|
||||
|
||||
mWorkerPoolExecutor = new ThreadPoolExecutor(mWorkerMaxCount, mWorkerMaxCount,
|
||||
0, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(),
|
||||
new PriorityThreadFactory(SpiderWorker.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND));
|
||||
@@ -538,7 +543,7 @@ public final class SpiderQueen implements Runnable {
|
||||
break;
|
||||
case STATE_FINISHED:
|
||||
synchronized (mDecodeRequestStack) {
|
||||
if (!mDecodeRequestStack.contains(index) && index != mDecodingIndex.get()) {
|
||||
if (!contain(mDecodeIndexArray, index) && !mDecodeRequestStack.contains(index)) {
|
||||
mDecodeRequestStack.add(index);
|
||||
mDecodeRequestStack.notify();
|
||||
}
|
||||
@@ -552,6 +557,15 @@ public final class SpiderQueen implements Runnable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean contain(int[] array, int value) {
|
||||
for (int v: array) {
|
||||
if (v == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ensureWorkers() {
|
||||
synchronized (mWorkerLock) {
|
||||
if (null == mWorkerPoolExecutor) {
|
||||
@@ -838,12 +852,13 @@ public final class SpiderQueen implements Runnable {
|
||||
// Ensure worker
|
||||
tryToEnsureWorkers();
|
||||
|
||||
// Start spider decoder
|
||||
Thread decoderThread = new PriorityThread(new SpiderDecoder(),
|
||||
"SpiderDecoder-" + sIdGenerator.incrementAndGet(),
|
||||
Process.THREAD_PRIORITY_DEFAULT);
|
||||
mDecoderThread = decoderThread;
|
||||
decoderThread.start();
|
||||
// Start decoder
|
||||
for (int i = 0; i < DECODE_THREAD_NUM; i++) {
|
||||
Thread decoderThread = new PriorityThread(new SpiderDecoder(i),
|
||||
"SpiderDecoder-" + i, Process.THREAD_PRIORITY_DEFAULT);
|
||||
mDecodeThreadArray[i] = decoderThread;
|
||||
decoderThread.start();
|
||||
}
|
||||
|
||||
// handle pToken request
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
@@ -907,9 +922,10 @@ public final class SpiderQueen implements Runnable {
|
||||
mQueenThread = null;
|
||||
|
||||
// Interrupt decoder
|
||||
Thread decoderThread = mDecoderThread;
|
||||
if (decoderThread != null) {
|
||||
decoderThread.interrupt();
|
||||
for (Thread decoderThread : mDecodeThreadArray) {
|
||||
if (decoderThread != null) {
|
||||
decoderThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupt all workers
|
||||
@@ -1278,6 +1294,18 @@ public final class SpiderQueen implements Runnable {
|
||||
|
||||
private class SpiderDecoder implements Runnable {
|
||||
|
||||
private final int mThreadIndex;
|
||||
|
||||
public SpiderDecoder(int index) {
|
||||
mThreadIndex = index;
|
||||
}
|
||||
|
||||
private void resetDecodeIndex() {
|
||||
synchronized (mDecodeRequestStack) {
|
||||
mDecodeIndexArray[mThreadIndex] = GalleryPageView.INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG_LOG) {
|
||||
@@ -1297,19 +1325,19 @@ public final class SpiderQueen implements Runnable {
|
||||
continue;
|
||||
}
|
||||
index = mDecodeRequestStack.pop();
|
||||
mDecodingIndex.lazySet(index);
|
||||
mDecodeIndexArray[mThreadIndex] = index;
|
||||
}
|
||||
|
||||
// Check index valid
|
||||
if (index < 0 || index >= mPageStateArray.length) {
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
resetDecodeIndex();
|
||||
notifyGetImageFailure(index, GetText.getString(R.string.error_out_of_range));
|
||||
continue;
|
||||
}
|
||||
|
||||
InputStreamPipe pipe = mSpiderDen.openInputStreamPipe(index);
|
||||
if (pipe == null) {
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
resetDecodeIndex();
|
||||
// Can't find the file, it might be removed from cache,
|
||||
// Reset it state and request it
|
||||
updatePageState(index, STATE_NONE, null);
|
||||
@@ -1323,14 +1351,12 @@ public final class SpiderQueen implements Runnable {
|
||||
pipe.obtain();
|
||||
// TODO how to keep stream open
|
||||
image = Image.decode(pipe.open(), false);
|
||||
if (image != null) {
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
} else {
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
if (image == null) {
|
||||
error = GetText.getString(R.string.error_decoding_failed);
|
||||
}
|
||||
resetDecodeIndex();
|
||||
} catch (IOException e) {
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
resetDecodeIndex();
|
||||
error = GetText.getString(R.string.error_reading_failed);
|
||||
} finally {
|
||||
pipe.close();
|
||||
|
||||
Reference in new issue
Block a user