Android優化筆記--多線程優化

        在Android項目中,我們創建的Service、Activity以及Broadcast均是一個主線程處理,這裏我們可以理解爲UI線程.但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數據庫操作以及網絡下載需要很長時間,爲了不阻塞用戶界面,出現ANR的響應提示窗口,這個時候我們可以考慮使用Thread線程來解決.先來簡單瞭解一下線程的調度原理及模型:

線程調度原理:
任一時刻,只有一個線程佔用CPU,處於運行狀態
多線程併發:
輪流獲取CPU使用權

線程調度模型:
分時調度模型:輪流獲取、均分CPU時間
搶佔式調度模型:優先級好的獲取,JVM採用這種方式。
nice值、cgroup

nice值:
1)Process中定義
2)值越小,優先級越高
3)默認是THREAD_PRIORITY_DEFAULT,0

cgroup:
1) 更嚴格的羣組調度策略。
2) 保證前臺線程可以獲取到更多的CPU
注意點:
線程過多會導致CPU頻繁切換,降低線程運行效率
正確認識任務重要性決定哪種優先級。 (工作量越大優先級越低)
優先級具有繼承性

常見使用方式:

不正確使用方式:
new  Thread(new  Runnable()  {
  @Override
  public  void  run()  {
    //執行業務
  }
}).start();

缺點:
a. 每次new Thread新建對象,性能相對較差;
b. 線程缺乏統一管理,可能無限制新建線程,相互之間競爭,及可能佔用過多系統資源導致anr死機或oom;

相比new Thread,Java提供的四種線程池的好處在於: 
1. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。 
2. 可有效控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。 
3. 提供定時執行、定期執行、單線程、併發數控制等功能。

四種線程池的創建方式:
newCacheThreadPool一個無限大並可以緩存的線程池。在之前創建新線程的時刻首先複用已經創建過的空閒線程。
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();


newFixedThreadPool 可以控制最大併發數的線程池。超過最大併發數的線程進入等待隊列
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

newScheduledThreadPool 一個可以定時執行的線程池。

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        scheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
               
            }
        },1, TimeUnit.SECONDS);


newSingleThreadExecutor 單線程化線程池。支持FIFO、LIFO的優先級執行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

以上都是在說創建線程池並且將業務代碼放到線程池中,如果應用中很多地方都需要多線程,如果我們都去new 線程池的話,就會造成線程池代碼冗餘,代碼閱讀性較差,這時我們需要一個線程池管理工具,如下:

public class AppExecutors {
    private static final String TAG = "AppExecutors";
    /**磁盤IO線程池**/
    private final ExecutorService diskIO;
	/**網絡IO線程池**/
    private final ExecutorService networkIO;
	/**UI線程**/
    private final Executor mainThread;
	/**定時任務線程池**/
    private final ScheduledExecutorService scheduledExecutor;

    public static AppExecutors getInstance() {
        if (appExecutors == null) {
            synchronized (AppExecutors.class) {
                if (appExecutors == null) {
                    appExecutors = new AppExecutors();
                }
            }
        }
        return appExecutors;
    }


    public AppExecutors(ExecutorService diskIO, ExecutorService networkIO, Executor mainThread, ScheduledExecutorService scheduledExecutor) {
        this.diskIO = diskIO;
        this.networkIO = networkIO;
        this.mainThread = mainThread;
        this.scheduledExecutor = scheduledExecutor;
    }

    public AppExecutors() {
        this(diskIoExecutor(), networkExecutor(), new MainThreadExecutor(), scheduledThreadPoolExecutor());
    }
	/**
	 * 定時(延時)任務線程池
	 * 
	 * 替代Timer,執行定時任務,延時任務
	 */
    public ScheduledExecutorService scheduledExecutor() {
        return scheduledExecutor;
    }

	/**
	 * 磁盤IO線程池(單線程)
	 * 
	 * 和磁盤操作有關的進行使用此線程(如讀寫數據庫,讀寫文件)
	 * 禁止延遲,避免等待
	 * 此線程不用考慮同步問題 
 	 */
    public ExecutorService diskIO() {
        return diskIO;
    }
	/**
	 * 網絡IO線程池
	 * 
	 * 網絡請求,異步任務等適用此線程
	 * 不建議在這個線程 sleep 或者 wait  
	 */
    public ExecutorService networkIO() {
        return networkIO;
    }

	/**
	 * UI線程
	 * 
	 * Android 的MainThread
	 * UI線程不能做的事情這個都不能做
	 */
    public Executor mainThread() {
        return mainThread;
    }

    private static ScheduledExecutorService scheduledThreadPoolExecutor() {
        return new ScheduledThreadPoolExecutor(16, r -> new Thread(r, "scheduled_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: scheduled executor queue overflow"));
    }

    private static ExecutorService diskIoExecutor() {
        return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), r -> new Thread(r, "disk_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: disk io executor queue overflow"));
    }

    private static ExecutorService networkExecutor() {
        return new ThreadPoolExecutor(3, 6, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(6), r -> new Thread(r, "network_executor"), (r, executor) -> Log.e(TAG, "rejectedExecution: network executor queue overflow"));
    }


    private static class MainThreadExecutor implements Executor {
        private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
            mainThreadHandler.post(command);
        }
    }
}

用法:

UI線程:

AppExecutors.getInstance().mainThread().execute(new Runnable() {
            @Override
            public void run() {
                //to do 
            }
        });

磁盤IO線程池:

AppExecutors.getInstance().diskIO().execute(new Runnable() {
            @Override
            public void run() {
                //to do
            }
        });

網絡IO線程池:

AppExecutors.getInstance().networkIO().execute(new Runnable() {
            @Override
            public void run() {
                //to do
            }
        });

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章