天天看點

線程與線程池的應用如有纰漏 敬請斧正

異步任務AsyncTask 源碼 位址 http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/os/AsyncTask.java

最近在Android開發上遇到線程遇到諸多問題,特此記錄下。也希望能為諸君貢獻一二。

Code一版

直接使用new Thread
new Thread(new Runnable() {
                @Override
                public void run() {
                    doSomething();//執行代碼(耗時等 資料庫操作等)
                }
            }).start();
           

很明顯的弊端,Code中太多地方需要線程的地方,new 了無數個線程。

1.每次new Thread建立對象性能差

2. 線程缺乏統一管理,可能無限制建立線程,互相之間競争,即可能占用過多的系統資源導緻當機

3.缺乏更多功能,比如定時執行,定期執行,線程中斷。

總之最後很紮心,而且你能想象這放在一個性能很差的Android機裡面運作麼~~

Code二版

使用定義的線程池

先來個我定義的

/**
 * 線程池管理(線程統一排程管理)
 */
public final class ThreadPoolManager {

    public static class ThreadPoolProxy {
        ThreadPoolExecutor mExecutor;
        private int mCorePoolSize;
        private int mMaximumPoolSize;
        /**
         * @param corePoolSize    核心池的大小
         * @param maximumPoolSize 最大線程數
         */
        public ThreadPoolProxy(int corePoolSize, int maximumPoolSize) {
            mCorePoolSize = corePoolSize;
            mMaximumPoolSize = maximumPoolSize;
        }

        /**
         * 初始化ThreadPoolExecutor
         * 雙重檢查加鎖,隻有在第一次執行個體化的時候才啟用同步機制,提高了性能
         */
        private void initThreadPoolExecutor() {
            if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
                synchronized (ThreadPoolProxy.class) {
                    if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
                        long keepAliveTime = 3000;
                        TimeUnit unit = TimeUnit.MILLISECONDS;
                        BlockingQueue workQueue = new LinkedBlockingDeque<>();
                        ThreadFactory threadFactory = Executors.defaultThreadFactory();
                        RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

                        mExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, keepAliveTime, unit, workQueue,
                                threadFactory, handler);
                    }
                }
            }
        }
        /**
         執行任務和送出任務的差別?
         1.有無傳回值
         execute->沒有傳回值
         submit-->有傳回值
         2.Future的具體作用?
         1.有方法可以接收一個任務執行完成之後的結果,其實就是get方法,get方法是一個阻塞方法
         2.get方法的簽名抛出了異常===>可以處理任務執行過程中可能遇到的異常
         */
        /**
         * 執行任務
         */
        public void execute(Runnable task) {
            initThreadPoolExecutor();
            mExecutor.execute(task);
        }

        /**
         * 送出任務
         */
        public Future submit(Runnable task) {
            initThreadPoolExecutor();
            return mExecutor.submit(task);
        }

        /**
         * 移除任務
         */
        public void remove(Runnable task) {
            initThreadPoolExecutor();
            mExecutor.remove(task);
        }
    }

    /**
     * 線程池工廠類
     * Created by Samson on 2018/2/11.
     * 使用方法
     * ThreadPoolProxyFactory .getNormalThreadPoolProxy().execute(Runnable);
     */

    public static class ThreadPoolProxyFactory {
        private static ThreadPoolProxy mNormalThreadPoolProxy;
        private static ThreadPoolProxy mDownLoadThreadPoolProxy;

        /**
         * 得到普通線程池代理對象mNormalThreadPoolProxy
         */
        public static ThreadPoolProxy getNormalThreadPoolProxy() {
            if (mNormalThreadPoolProxy == null) {
                synchronized (ThreadPoolProxyFactory.class) {
                    if (mNormalThreadPoolProxy == null) {
                        mNormalThreadPoolProxy = new ThreadPoolProxy(10 , 10);
                    }
                }
            }
            return mNormalThreadPoolProxy;
        }
        /**
         * 下載下傳專用
         * 得到下載下傳線程池代理對象mDownLoadThreadPoolProxy
         */
        public static ThreadPoolProxy getDownLoadThreadPoolProxy() {
            if (mDownLoadThreadPoolProxy == null) {
                synchronized (ThreadPoolProxyFactory.class) {
                    if (mDownLoadThreadPoolProxy == null) {
                        mDownLoadThreadPoolProxy = new ThreadPoolProxy(3, 3);
                    }
                }
            }
            return mDownLoadThreadPoolProxy;
        }
    }
}
           

如何使用:

ThreadPoolManager.ThreadPoolProxyFactory.getNormalThreadPoolProxy()
                  .execute(new Runnable() {
                                  @Override
                                    public void run() {
                                          doSomething();
                                     }
                 });
-----------------------------------------lambda
ThreadPoolManager.ThreadPoolProxyFactory.getNormalThreadPoolProxy()
        .execute(() -> {doSomething();});
           

Code三版

手動控制版線程池(将所有事務分類放在規定的線程中執行,(未不同類别的事務規定不同的線程))
/**
 * 本地資料處理和耗時處理用不同線程處理
 */

public class ThreadPoolUtil {

    private List<Run> runList = new ArrayList<>();
    private List<Run> runListTemp = new ArrayList<>();
    private Thread thread = null;

    public interface Run {
        void run();
    }

    private ThreadPoolUtil() {
        init();
    }

    private void init() {
        if (thread == null) {
            thread = new Thread(() -> {
                for (; ; ) {
                    synchronized (lock) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    dealRun();
                }
            });
            thread.start();
        }
    }

    private final Object lock = new Object();
    private static ThreadPoolUtil _INSTANCESEND = null;
    private static ThreadPoolUtil _INSTANCESERVER = null;
    private static ThreadPoolUtil _INSTANCENORMAL = null;

    /**
     *  發消息
     * @return
     */
    public static ThreadPoolUtil getSendMsgInstance() {
        if (_INSTANCESEND == null) {
            _INSTANCESEND = new ThreadPoolUtil();
        }
        return _INSTANCESEND;
    }
    /**
     *  收消息
     * @return
     */
    public static ThreadPoolUtil getGetMsgInstance() {
        if (_INSTANCESERVER == null) {
            _INSTANCESERVER = new ThreadPoolUtil();
        }
        return _INSTANCESERVER;
    }
    /**
     *  普通通用消息
     * @return
     */
    public static ThreadPoolUtil getNormalInstance() {
        if (_INSTANCENORMAL == null) {
            _INSTANCENORMAL = new ThreadPoolUtil();
        }
        return _INSTANCENORMAL;
    }


    public void addRun(Run run) {
        runListTemp.add(run);
        synchronized (lock) {
            runList.addAll(runListTemp);
            runListTemp.clear();
            lock.notify();
        }
    }

    private Run getRun() {
        if (runList.size() <= 0) {
            return null;
        }
        Run run = null;
        synchronized (lock) {
            run = runList.get(0);
            runList.remove(0);
        }
        return run;
    }

    private void dealRun() {
        try {
            for (Run run = getRun(); (run) != null; ) {
                run.run();
                run = getRun();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           

如何使用:不同的分類可 get 不同的線程來處理。

ThreadPoolUtil.getNormalInstance().addRun(new ThreadPoolUtil.Run() {
                @Override
                public void run() {
                     doSomething();
                }
            });
-----------------------------------------lambda
ThreadPoolUtil.getNormalInstance().addRun(() ->{
                doSomething();
            });
           

2,3兩種方式 差別

2方式一旦有線程操作失誤可能會導緻全線線程癱瘓,導緻整個線程池無法正常的運作下去,

3方式使用失誤 基本隻會導緻其一線程癱瘓,更易于查找 修複。

至于其他優勢 仍在探究中...

如有纰漏 敬請斧正