본문 바로가기

Android

Executors.newSingleThreadExecutor 동작 테스트

보통 async task 를 inner class 를 바로 인스턴스 하는 형태로 쓰다가 메모리 닉 문제가 있다보니 별도의 static 클래스로 구성하여
사용했는데 쓰던 버릇이 있어서 이게 좀 귀찮았다.

그러던 차에 Executors 에 대해 알게 되었고 이를 사용하는데 이 녀석이 어떻게 동작하는지에 대해서
알아야할 필요성이 있어서 잠시 테스트를 시도 했다.

Executors.newSingleThreadExecutor 을 이용시 일반적인 AsyncTask 의 execute 처럼
동작하는지 아니면 executeOnExecutor 처럼 동작하는지를 확인할 테스트 코드로 아래와 같이 구성하였고

static Integer mCount = 0;

    static class TestAsyncTask extends AsyncTask<Void, Boolean, Boolean> {
        @Override
        protected Boolean doInBackground(Void... voids) {
            try {
                Thread.sleep(1000);

                synchronized (mCount) {
                    if (mLog.isDebugEnabled()) {
                        mLog.debug("THREAD : " + mCount++);
                    }
                }
            } catch (Exception e) {
                mLog.error("ERROR: " + e.getMessage());
            }
            return null;
        }
    }

    static class TestAsyncTask2 extends AsyncTask<Void, Boolean, Boolean> {
        @Override
        protected Boolean doInBackground(Void... voids) {
            try {
                Thread.sleep(1000);

                synchronized (mCount) {
                    if (mLog.isDebugEnabled()) {
                        mLog.debug("THREAD2 : " + mCount++);
                    }
                }
            } catch (Exception e) {
                mLog.error("ERROR: " + e.getMessage());
            }
            return null;
        }
    }

이렇게 AsyncTask 를 생성하고 click 이벤트를 통해 테스트를 진행 했다.

btn.setOnClickListener(v -> {
            new TestAsyncTask().execute();
            new TestAsyncTask().execute();
            new TestAsyncTask2().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            new TestAsyncTask2().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

            Executors.newSingleThreadExecutor().execute(() -> {
                try {
                    Thread.sleep(1000);

                    synchronized (mCount) {
                        if (mLog.isDebugEnabled()) {
                            mLog.debug("(EXECUTOR 1) : " + mCount++);
                        }
                    }
                } catch (Exception e) {

                }
            });

            Executors.newSingleThreadExecutor().execute(() -> {
                try {
                    Thread.sleep(500);

                    synchronized (mCount) {
                        if (mLog.isDebugEnabled()) {
                            mLog.debug("EXECUTOR 2 : " + mCount++);
                        }
                    }
                } catch (Exception e) {

                }
            });
        });

결과로 출력된 로그는 아래와 같다.

D/[HSP]: MainActivity.lambda$null$2$MainActivity(MainActivity.java:126) EXECUTOR 2 : 0
D/[HSP]: MainActivity.lambda$null$1$MainActivity(MainActivity.java:112) (EXECUTOR 1) : 1
D/[HSP]: MainActivity$TestAsyncTask2.doInBackground(MainActivity.java:168) THREAD2 : 2
D/[HSP]: MainActivity$TestAsyncTask2.doInBackground(MainActivity.java:168) THREAD2 : 3
D/[HSP]: MainActivity$TestAsyncTask.doInBackground(MainActivity.java:150) THREAD : 4
D/[HSP]: MainActivity$TestAsyncTask.doInBackground(MainActivity.java:150) THREAD : 5

executeOnExecutor 처럼 동작하는 것 그리고 더 찾아봐야겠지만 AsyncTask 보다 우선권이 있다는것
SERIAL 하게 동작을 원한다면 AsyncTask 를 아니면 Executors.newSingleThreadExecutors 를
사용해도록 결정..

일단 Rx 를 위해서도 submit() 을 이용해 Future 로 Observable 를 생성할 수 있어서 연관성이 있다.