android开发笔记之异步ThreadPoolExecutor

android开发笔记之异步ThreadPoolExecutorandroid异步开发android异步开发,主要有1.Thread+Handler进行异步处理2.继承Thread类和实现Runnable接口3.AsyncTask类4.RxJava5.AsyncQueryHandler但是事实上AsyncTask是有缺点的。syncTaskisdesignedtobeahelperclassaroundThreadandH…

大家好,又见面了,我是你们的朋友全栈君。

android异步开发

android异步开发,主要有
1.Thread+Handler进行异步处理
2.继承Thread类和实现Runnable接口
3.AsyncTask类
4.RxJava
5.AsyncQueryHandler

但是事实上AsyncTask是有缺点的。

syncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

AsyncTask是一个帮助类,它非常适合一个后台短耗时操作(最多几秒)。如果你要使后台进程保持运行非常长的时间,强烈推荐你使用 Executor, ThreadPoolExecutor 和FutureTask。

所以下面我们就看看ThreadPoolExecutorFutureTask的使用方法.

ThreadPoolExecutor

我们直接查看android源码中ThreadPoolExecutor的使用情况:

grep -rni --include=*.java "ThreadPoolExecutor "  ./packages/ 
./packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java:113:    
private ThreadPoolExecutor mExecutor;
./packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java:124:        
// Executors#newSingleThreadExecutor creates a ThreadPoolExecutor but it returns the

具体我们查看关键的源码:
packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java

public final class DictionaryService extends Service {

    /**
     * An executor that serializes tasks given to it.
     */
    private ThreadPoolExecutor mExecutor;
    private static final int WORKER_THREAD_TIMEOUT_SECONDS = 15;

    @Override
    public void onCreate() {
        mExecutor = new ThreadPoolExecutor(1 /* corePoolSize */, 1 /* maximumPoolSize */,
                WORKER_THREAD_TIMEOUT_SECONDS /* keepAliveTime */,
                TimeUnit.SECONDS /* unit for keepAliveTime */,
                new LinkedBlockingQueue<Runnable>() /* workQueue */);
        mExecutor.allowCoreThreadTimeOut(true);
    }

    @Override
    public synchronized int onStartCommand(final Intent intent, final int flags,
            final int startId) {
            ........................
            mExecutor.submit(new Runnable() {
                @Override
                public void run() {
                ..........................
            });

其实上面也就给出了ThreadPoolExecutor 的一个使用样例了。

我们仿照上面的例子,写一个Demo:

我们使用ThreadPoolExecutor 来实现一个后台的60秒的耗时操作,然后再通过handler更新UI界面。

public class MainActivity extends AppCompatActivity {

    private final static String TAG = "MainActivity";

    private final static int UPDEAT_UI =1;

    private TextView textView;
    private Button button_ThreadPoolExecutor;

    private ThreadPoolExecutor mExecutor;
    private static final int WORKER_THREAD_TIMEOUT_SECONDS = 15;

    private  Handler handler =  new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch(msg.what){
                case UPDEAT_UI:
                    //Toast.makeText(getApplication(),"on do long funtion",Toast.LENGTH_LONG).show();
                    textView.setText("UPDEAT_UI--ThreadPoolExecutor");
                    Log.i(TAG,"handler.handleMessage--UPDEAT_UI");
                    break;
                default :
                    break;
            }
        }
    };

    private  Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //on do long time function
            try {
                Thread.sleep(1000*60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG,"handler.sendEmptyMessage--UPDEAT_UI");
            handler.sendEmptyMessage(UPDEAT_UI);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    private void init() {
        mExecutor = new ThreadPoolExecutor(
                1 /* corePoolSize */,
                1 /* maximumPoolSize */,
                WORKER_THREAD_TIMEOUT_SECONDS /* keepAliveTime */,
                TimeUnit.SECONDS /* unit for keepAliveTime */,
                new LinkedBlockingQueue<Runnable>() /* workQueue */);
        mExecutor.allowCoreThreadTimeOut(true);

        textView = (TextView) findViewById(R.id.textView);

        button_ThreadPoolExecutor = (Button) findViewById(R.id.button_ThreadPoolExecutor);
        button_ThreadPoolExecutor.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i(TAG,"button_ThreadPoolExecutor---onClick");
                //mExecutor.submit(runnable);
                mExecutor.execute(runnable);
            }
        });
    }
}

构造函数

ThreadPoolExecutor(
 int corePoolSize,
 int maximumPoolSize, 
 long keepAliveTime, 
 TimeUnit unit, 
 BlockingQueue<Runnable> workQueue,
  ThreadFactory threadFactory, 
  RejectedExecutionHandler handler) 

这个是ThreadPoolExecutor完整的构造器,其他的构造器其实也是在内部调用这个.

corePoolSize 核心线程数,线程池保留线程的数量,即使这些线程是空闲.除非设置了allowCoreThreadTimeOut
maximumPoolSize 线程池最大允许的线程数.
keepAliveTime 当当前的线程数大于核心线程数,那么这些多余的空闲的线程在被终止之前能等待新任务的时间.
unit keepAliveTime时间的单位
workQueue 这个是用来保留将要执行的工作队列.
threadFactory 用于创建新线程的工厂
handler 如果工作队列(workQueue)满了,那么这个handler是将会被执行.

Android中的线程池的分类

通过配置不同参数的ThreadPoolExecutor, 有4类常用的线程池, Executors类提供了4个工厂方法用于创建4种不同特性的线程池给开发者用.

FixedThreadPool
用法:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(num);
fixedThreadPool.execute(runnable对象);
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());
}

特点:只有核心线程数,并且没有超时机制,因此核心线程即使闲置时,也不会被回收,因此能更快的响应外界的请求.

CachedThreadPool
用法:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable对象);
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                              60L, TimeUnit.SECONDS,
                              new SynchronousQueue<Runnable>());
}

特点:没有核心线程,非核心线程数量没有限制, 超时为60秒.
适用于执行大量耗时较少的任务,当线程闲置超过60秒时就会被系统回收掉,当所有线程都被系统回收后,它几乎不占用任何系统资源.

ScheduledThreadPool
用法:

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
scheduledThreadPool.schedule(runnable对象, 2000, TimeUnit.MILLISECONDS);
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

特点:核心线程数是固定的,非核心线程数量没有限制, 没有超时机制.
主要用于执行定时任务和具有固定周期的重复任务.

SingleThreadExecutor

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(runnable对象);
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>()));
}

特点:只有一个核心线程,并没有超时机制.
意义在于统一所有的外界任务到一个线程中, 这使得在这些任务之间不需要处理线程同步的问题.

Android中的四种线程池的使用源码

我们在源码中搜索ExecutorService,会发现大把的使用样例。下面我们就简单的列举几个吧。

Executors.newSingleThreadExecutor

packages\apps\SnapdragonGallery\src\com\android\photos\drawables\AutoThumbnailDrawable.java

private static ExecutorService sThreadPool = Executors.newSingleThreadExecutor();
sThreadPool.execute(mLoadBitmap);
.........................................
    private final Runnable mLoadBitmap = new Runnable() {
        @Override
        public void run() {
      
        }
    };

packages\apps\Contacts\src\com\android\contacts\vcard\VCardService.java

    // Should be single thread, as we don't want to simultaneously handle import and export
    // requests.
    private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
   ........................
   Log.d(LOG_TAG, "Executor service status: shutdown: " + mExecutorService.isShutdown()
                        + ", terminated: " + mExecutorService.isTerminated());
........................
    /**
     * Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
     * @return true when successful.
     */
   private synchronized boolean tryExecute(ProcessorBase processor) {
        try {
            mExecutorService.execute(processor);
            return true;
        } catch (RejectedExecutionException e) {
            Log.w(LOG_TAG, "Failed to excetute a job.", e);
            return false;
        }
    }
........................
        Log.i(LOG_TAG, "No unfinished job. Stop this service.");
        mExecutorService.shutdown();
........................
        if (mExecutorService.isShutdown()) {
            Log.w(LOG_TAG, "MediaScanner update is requested after executor's being shut down. " +
                    "Ignoring the update request");
            return;
        }        
........................
mExecutorService.shutdown();

Executors.newCachedThreadPool

packages\apps\Dialer\java\com\android\voicemail\impl\fetch\FetchVoicemailReceiver.java

  private void fetchVoicemail(final Network network, final VoicemailStatus.Editor status) {
    Executor executor = Executors.newCachedThreadPool();
    executor.execute(
        new Runnable() {
          @Override
          public void run() {
         ................................................
          }
        });
  }

Executors.newFixedThreadPool

packages\apps\CMFileManager\src\com\cyanogenmod\filemanager\providers\SecureResourceProvider.java

private final ExecutorService mExecutorService = Executors.newFixedThreadPool(1);
...............................
mExecutorService.execute(new Runnable() {
                @Override
                public void run() {
                    ....................
                }
            });

Executors.newScheduledThreadPool

packages\apps\Dialer\java\com\android\dialer\app\voicemail\VoicemailPlaybackPresenter.java

private static ScheduledExecutorService mScheduledExecutorService;
......................
  private static synchronized ScheduledExecutorService getScheduledExecutorServiceInstance() {
    if (mScheduledExecutorService == null) {
      mScheduledExecutorService = Executors.newScheduledThreadPool(NUMBER_OF_THREADS_IN_POOL);
    }
    return mScheduledExecutorService;
  }
...........................
  /** Must be invoked when the parent activity is destroyed. */
  public void onDestroy() {
    // Clear references to avoid leaks from the singleton instance.
    mActivity = null;
    mContext = null;
    if (mScheduledExecutorService != null) {
      mScheduledExecutorService.shutdown();
      mScheduledExecutorService = null;
    }
 }

代码最后调用跳转到这个runnable:
\packages\apps\Dialer\java\com\android\dialer\app\voicemail\VoicemailPlaybackLayout.java

 /** Controls the animation of the playback slider. */
  @ThreadSafe
  private final class PositionUpdater implements Runnable {

    /** Update rate for the slider, 30fps. */
    private static final int SLIDER_UPDATE_PERIOD_MILLIS = 1000 / 30;

    private final ScheduledExecutorService mExecutorService;
    @GuardedBy("mLock")
    private ScheduledFuture<?> mScheduledFuture;

.........................
        mScheduledFuture = mExecutorService.scheduleAtFixedRate(
                this, 0, SLIDER_UPDATE_PERIOD_MILLIS, TimeUnit.MILLISECONDS);
...........................
      if (mScheduledFuture != null) {
        mScheduledFuture.cancel(true);
        mScheduledFuture = null;
      }

参考资料

1.Class ThreadPoolExecutor
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
2.(十七)java多线程之ThreadPoolExecutor
https://segmentfault.com/a/1190000009111732
3.android中的线程池 ThreadPoolExecutor
https://www.jianshu.com/p/86eb8ea62141
4.ThreadPoolExecutor使用示例
https://cwind.iteye.com/blog/2286567

写在后面的话

为什么好久没有写博客,今天又开始写呢.

主要是最近看了一下一个Android面试一天一题,感觉这个作者android技术非常的棒,但是对技术还是这么热情.而对比自己,android技术的深度和广度都有欠缺,虽然平时开发没有什么问题,但是面试还是被别人diss.不一定别人就比我厉害,只是自己还是对一些平时有疑问的技术没有更深入的进一步了解.

就比如这个ThreadPoolExecutor 和FutureTask,其实早在几年前就想了解一下,但是就是没有进一步的去实践,那后面就再进一步把以前自己想做的事再做一次吧,去完成自己以前留下的小尾巴吧.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158706.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 模电知识总结(一)

    模电知识总结(一)半导体的基本特性半导体的物理基础:1.掺杂特性2.热敏特性3.光敏特性2.本征半导体:原子排列整齐、晶格无缺陷、纯净的半导体(在热力学温度零度,由于共价键的束缚,价电子能量无法挣脱共价键的束缚,因此晶体中没有自由电子,此时半导体相当于绝缘体。)本征半导体的导电能力很差。(载流子浓度与原子密度相比很少)本征激发(热激发):由热能产生电子-空穴对的现象。随着温度升高,载流子浓度(指数)增加,其电阻率的温度系数是负的,这是半导体导电与金属导电的根本不同点。(相同温度下,锗的载流子浓度大于硅。)

    2022年6月20日
    27
  • CentOS 6.4安装(超级详细图解教程)

    CentOS 6.4安装(超级详细图解教程)说明:1、CentOS6.4系统镜像有两个,安装系统只用到第一个镜像即CentOS-6.4-i386-bin-DVD1.iso(32位)或者CentOS-6.4-x86_64-bin-DVD1.i

    2022年7月3日
    19
  • 图形推理题_图形推理必做100题答案

    图形推理题_图形推理必做100题答案一、轴对称和中心对称的判定1、把下面的六个图形分为两类,使每一类图形都有各自的共同特征或规律,分类正确的一项是:A.①③④,②⑤⑥B.①③⑤,②④⑥C.①②⑥,③④⑤D.①④⑥,②③

    2022年8月2日
    5
  • java的三种代码注释方式「建议收藏」

    java的三种代码注释方式「建议收藏」1.注释的作用注释是对程序语言的说明,有助于开发者之间的交流,方便理解和维护程序。注释不是编程语句,不会被编译器执行。一些代码量少较少的程序,我们加不加注释对我们的理解和修改代码没有太大影响;如果是淘宝;抖音等那种中大型程序,没有了代码注释,对于日后程序运行维护将是很大困难。我们可以在平时编码过程中养成规范代码注释习惯,也是我们成为优秀程序员的原因2.java中的注释分类Java中的注释分为以下三种:单行注释;多行注释;文档注释1.单行注释java代码中使用双斜杠单行注释//,一般单行注释,注释少

    2022年7月7日
    22
  • 测试用例八大要素及额外十小要素

    测试用例八大要素及额外十小要素测试用例八大要素1.测试用例编号由字母、字符、数字组合而成的字符串,有唯一性,易识别性。eg:1)系统测试:产品编号-ST-系统测试项名-系统测试子项名-编号2)集成测试:产品编号-IT-集成测试项名-集成测试子项名-编号3)单元测试:产品编号-UT-单元测试项名-单元测试子项名-编号这样看到编号就可以知道是做的什么测试,测试的对象是什么,也方便维护。 2.测…

    2022年6月28日
    23
  • genre-based_deepsort特征判断

    genre-based_deepsort特征判断  https://arxiv.org/abs/1804.01438https://blog.csdn.net/gavinmiaoc/article/details/80648754https://zhuanlan.zhihu.com/p/35296881 https://github.com/seathiefwang/MGN-pytorch

    2022年9月26日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号