개요
자바의 실행자(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(); } }
BlockingQueue preloadedQueue = 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에 대해서 배워보자