개요
자바의 실행자(Executor) 프레임워크는 스레드에 대해 그리고 시스템에서 스레드가 사용하는 자원에 대한 새로운 차원의 제어를 가능하게 한다.
Executor 프레임워크에 관련된 클래스를 사용하면 시스템이 스레드 수를 관리하거나 더 이상 필요하지 않은 스레드를 취소 할 수 있다.
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
@Override
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Executors.newFixedThreadPool(10, new LowPriorityThreadFactory());
}
static class LowPriorityThreadFactory implements ThreadFactory {
private static int count = 1;
private static String TAG = "LowPriorityThreadFactory";
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("LowPrio " + count++);
t.setPriority(4);
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable throwable) {
Log.d(TAG, "Thread = " +t.getName() + ", error = " + throwable.getMessage());
}
});
return t;
}
}
public class TaskTrackingThreadPool extends ThreadPoolExecutor {
private AtomicInteger mTaskCount = new AtomicInteger(0);
public TaskTrackingThreadPool() {
super(3,3,0L,TimeUnit.SECONDS, new LinkedBlockingQueue());
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
mTaskCount.getAndIncrement();
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
mTaskCount.getAndIncrement();
}
public int getNbrOfTasks() {
return mTaskCount.get();
}
}
BlockingQueuepreloadedQueue = new LinkedBlockingQueue (); final String[] alphabat = {"Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta"}; for (int i = 0; i < alphabat.length; i++) { final int j = i; preloadedQueue.add(new Runnable() { @Override public void run() { //긴 동작들 } }); } ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS, preloadedQueue); executor.prestartAllCoreThreads();
@UiThread
public void onButtonClick(View v) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
List> tasks = new ArrayList>();
tasks.add(new Callable() {
@Override
public String call() throws Exception {
return getFirstDataFromNetwork();
}
});
tasks.add(new Callable() {
@Override
public String call() throws Exception {
return getSecondDataFromNetwork();
}
});
ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
List> futures = executorService.invokeAll(tasks);
String mashedData = mashupResult(futures);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();
}
});
}
private String getFirstDataFromNetwork() {
// 네트워크 호출
return "1";
}
private String getSecondDataFromNetwork() {
//네트워크 호출
return "2";
}
private String mashupResult(List> futures) throws InterruptedException {
for (Future future : futures) {
// data = futures.get() 으로 결과 얻음
}
return "data";
}
private LinearLayout layoutImages;
private class ImageDownloadTask implements Callable {
@Override
public Bitmap call() throws Exception {
return downloadRemoteImage();
}
private Bitmap downloadRemoteImage() {
// 이미지 다운로드 실행
return null;
}
}
private class DownloadCompletionService extends ExecutorCompletionService {
private ExecutorService mExecutor;
public DownloadCompletionService(ExecutorService executor) {
super(executor);
mExecutor = executor;
}
public void shutdown() {
mExecutor.shutdown();
}
public boolean isTerminated() {
return mExecutor.isTerminated();
}
}
private class ConsumerThread extends Thread {
private DownloadCompletionService mEcs;
private ConsumerThread(DownloadCompletionService ecs) {
this.mEcs = ecs;
}
@Override
public void run() {
super.run();
try {
while (!mEcs.isTerminated()) {
Future future = mEcs.poll(1, TimeUnit.SECONDS);
if (future != null) {
addImage(future.get());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
private void addImage(final Bitmap image) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ImageView iv = new ImageView(MainActivity.this);
iv.setImageBitmap(image);
layoutImages.addView(iv);
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
DownloadCompletionService ecs = new DownloadCompletionService(Executors.newCachedThreadPool());
new ConsumerThread(ecs).start();
for (int i = 0; i < 5; i++) {
ecs.submit(new ImageDownloadTask());
}
ecs.shutdown();
9.5 마치며
Executor 프레임 워크는 안드로이드 비동기 기술의 토대를 제공한다. 해당 기법을 이용하면 더 정교한 방법으로 동시성을 관리하게 해준다. 다음시간에는 안드로이드 대표 기술인 AsyncTask에 대해서 배워보자