X

スレッドプライオリティ(優先度)を変更する

Androidでスレッドの優先度を指定する方法を紹介します。Androidアプリケーションでは、UIスレッドで時間のかかる処理を行ってしまうと応答性に影響が出るのは周知の事実です。たとえば次のような処理はUIスレッドに適さないでしょう。

  • アプリ外部:ネットワークやローカルファイル、データベース、ソケットへのアクセスする場合
  • アプリ内部:ブロッキング(synchronized等)を利用したクリティカルセクションがある場合
  • CPU時間:CPUを長く拘束する処理。たとえば画像処理のような時間がかかることがあらかじめ分かっている場合

さまざまな理由があってマルチスレッド化を検討すると思いますが、スレッドの優先度まで気にすることは稀です。それは上記で示した多くの例ではUIスレッドを守るため別スレッドに追い出す処理だから(=UIスレッドに比べて優先度が低いから)です。他のリソースに依存した待ち時間は優先度を高くしても効果が見込めません。

しかしながらVoIPの音声デコードやストリーム動画の受信などデータや処理に時間的な制約がある場合、スレッドの優先度を変える選択肢が取り得ます。その場合はスレッドを1つ作成し、ごく短い時間で処理を完了することをおすすめします。たくさんのスレッドをつかって細かく優先度を変えることは、制御の複雑化につながる可能性があります。

優先度を設定する

Androidではandroid.os.ProcessクラスのsetThreadPriorityメソッドを使えばスレッドの優先度を変更できます。

  • android.os.Process.setThreadPriority (int tid, int priority)メソッド
  • android.os.Process.setThreadPriority (int priority)メソッド

即値 定数 説明
19 THREAD_PRIORITY_LOWEST 最も優先度が低いスレッドです。通常利用しません
10 THREAD_PRIORITY_BACKGROUND バックグラウンド処理に最適な優先度です。デフォルトより低い優先度にすることで応答性への影響を最小限にしています
1 THREAD_PRIORITY_LESS_FAVORABLE 標準的な優先度より、ほんの少し優先を下げた設定値です
0 THREAD_PRIORITY_DEFAULT アプリのスレッドとして標準的な優先度です
-1 THREAD_PRIORITY_MORE_FAVORABLE 標準的な優先度より、ほんの少し優先を上げた設定値です
-2 THREAD_PRIORITY_FOREGROUND UIスレッドの設定値です。システムがUIスレッドを作る際に利用します。通常、アプリ開発者は利用しません
-4 THREAD_PRIORITY_DISPLAY システムがUIを更新するために使う表示用スレッドの設定値です。通常、アプリ開発者は利用しません
-8 THREAD_PRIORITY_URGENT_DISPLAY システムが画面描画やInputDevice情報を処理するための設定値です。非常に優先度が高いため、通常、アプリ開発者は使用しません
-16 THREAD_PRIORITY_AUDIO オーディオ処理のための設定値です。アプリケーションは通常、この優先度に変更できません
-19 THREAD_PRIORITY_URGENT_AUDIO オーディオ処理を最優先で行うための設定値です。アプリケーションは通常、この優先度に変更できません

Linuxの優先度に準じており、優先度(nice値)は最も高い-20から最も低い19まで変更可能です。表からはUIスレッドを超える優先度を設定する場合は描画処理や音声処理など一部の用途が利用しているだけということがわかります。高い優先度をつけたい場合は、処理を分散できないか、ロジックの高速化して対応できないかなど十分に検討してください。

サンプルコードで優先度を指定したスレッドを作るThreadFactoryを見てみましょう。

■PriorityThreadFactory.java

    public class PriorityThreadFactory implements ThreadFactory {
        private final int mPriority;
        private final AtomicInteger mNumber = new AtomicInteger();
        private final String mName;

        public PriorityThreadFactory(String name, int priority) {
            mName = name;
            mPriority = priority;
        }

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, mName + '-' + mNumber.getAndIncrement()) {

                @Override
                public void run() {
                    // android.os.Processを使う場合 : Process.THREAD_PRIORITY_DEFAULT
                    android.os.Process.setThreadPriority(mPriority);

                    // java.lang.Threadを使う場合 : Thread.NORM_PRIORITY
                    // this.setPriority( mPriority );

                    super.run();
                }
            };
        }
    }

PriorityThreadFactoryクラスのコンストラクタで受けとった優先度(mPriority)をandroid.os.Process.setThreadPriorityメソッドで指定しています。

サンプルでは参考までにjava.lang.Thread.setPriorityメソッドでの設定方法も紹介しています。この場合は定数値が異なりますがスレッドの優先度は次の通りです。

  • java.lang.Thread.setPriority(int priority)メソッド

定数値 説明
MIN_PRIORITY android.os.Process.THREAD_PRIORITY_LOWEST同等(定数値は異なる)
NORM_PRIORITY android.os.Process.THREAD_PRIORITY_DEFAULT同等(定数値は異なる)
MAX_PRIORITY android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY同等(定数値は異なる)

java.lang.Thread.setPriorityメソッドでも設定は可能ですが、表のとおり数が少ないため移植性等を考慮しなければandroid.os.Process.setThreadPriorityメソッドを優先すると良いでしょう(反対にjava.lang.Thread.setPriorityメソッドを使っているライブラリなど他環境から移植した場合でも、不具合が無ければandroid.os.Process.setThreadPriorityメソッドに置き換える必要はありません)。

以上、おつかれさまでした。

mhidaka: Software Engineerだよ。DroidKaigi Organizer / Androidと組込とRe:VIEW。techbooster主宰。mhidaka's writings http://booklog.jp/users/mhidaka 技術書典! http://techbookfest.org
Related Post