forked from facebook/fresco
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Single threaded executor for image decoding
- Loading branch information
Showing
3 changed files
with
190 additions
and
4 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
fbcore/src/main/java/com/facebook/common/executors/SerialDelegatingExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
package com.facebook.common.executors; | ||
|
||
import javax.annotation.concurrent.GuardedBy; | ||
|
||
import java.util.LinkedList; | ||
import java.util.Queue; | ||
import java.util.concurrent.Executor; | ||
|
||
import com.facebook.common.internal.Preconditions; | ||
import com.facebook.common.internal.VisibleForTesting; | ||
|
||
/** | ||
* Simple implementation of delegating Executor that limits concurrency of execution to single | ||
* thread. | ||
*/ | ||
public class SerialDelegatingExecutor implements Executor { | ||
|
||
private final Executor mDelegate; | ||
@VisibleForTesting | ||
final Runnable mRunnable; | ||
|
||
/** | ||
* True if and only if runnable has been passed to mDelegate for execution, but the execution | ||
* itself has not completed yet. | ||
*/ | ||
@GuardedBy("this") | ||
@VisibleForTesting | ||
boolean mExecutionInProgress; | ||
@GuardedBy("this") | ||
final private Queue<Runnable> mCommands; | ||
|
||
public SerialDelegatingExecutor(Executor delegate) { | ||
mDelegate = Preconditions.checkNotNull(delegate); | ||
mExecutionInProgress = false; | ||
mCommands = new LinkedList<Runnable>(); | ||
mRunnable = new Runnable() { | ||
@Override | ||
public void run() { | ||
executeSingleCommand(); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Submits another command for execution | ||
*/ | ||
@Override | ||
public void execute(Runnable command) { | ||
synchronized (this) { | ||
mCommands.add(command); | ||
} | ||
maybeSubmitRunnable(); | ||
} | ||
|
||
private void maybeSubmitRunnable() { | ||
synchronized (this) { | ||
if (mExecutionInProgress || mCommands.isEmpty()) { | ||
return; | ||
} | ||
mExecutionInProgress = true; | ||
} | ||
mDelegate.execute(mRunnable); | ||
} | ||
|
||
private void executeSingleCommand() { | ||
Runnable command; | ||
try { | ||
removeNextCommand().run(); | ||
} finally { | ||
clearExecutionInProgress(); | ||
maybeSubmitRunnable(); | ||
} | ||
} | ||
|
||
private synchronized Runnable removeNextCommand() { | ||
return mCommands.remove(); | ||
} | ||
|
||
private synchronized void clearExecutionInProgress() { | ||
mExecutionInProgress = false; | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
fbcore/src/test/java/com/facebook/common/executors/SerialDelegatingExecutorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
package com.facebook.common.executors; | ||
|
||
import java.util.concurrent.Executor; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import static org.mockito.Mockito.*; | ||
|
||
public class SerialDelegatingExecutorTest { | ||
private SerialDelegatingExecutor mSerialDelegatingExecutor; | ||
private Executor mExecutor; | ||
private Runnable mRunnable; | ||
|
||
@Before | ||
public void setUp() { | ||
mExecutor = mock(Executor.class); | ||
mSerialDelegatingExecutor = new SerialDelegatingExecutor(mExecutor); | ||
mRunnable = mock(Runnable.class); | ||
} | ||
|
||
@Test | ||
public void testSubmitsTask() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
|
||
verify(mExecutor).execute(mSerialDelegatingExecutor.mRunnable); | ||
} | ||
|
||
@Test | ||
public void testExecutesTask() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
|
||
verify(mRunnable).run(); | ||
} | ||
|
||
@Test | ||
public void testDoesNotSubmitMultipleRunnables() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
|
||
verify(mExecutor).execute(mSerialDelegatingExecutor.mRunnable); | ||
} | ||
|
||
@Test | ||
public void testDoesSubmitNextRunnable() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
|
||
verify(mExecutor, times(2)).execute(mSerialDelegatingExecutor.mRunnable); | ||
} | ||
|
||
@Test | ||
public void testExecutesMultipleTasks() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
|
||
verify(mRunnable, times(2)).run(); | ||
} | ||
|
||
@Test | ||
public void testDoesNotSubmitRunnableTooManyTimes() { | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.execute(mRunnable); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
mSerialDelegatingExecutor.mRunnable.run(); | ||
|
||
verify(mExecutor, times(2)).execute(mSerialDelegatingExecutor.mRunnable); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters