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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mac平台adb、tcpdump捕手android移动网络数据包

    mac平台adb、tcpdump捕手android移动网络数据包

    2022年1月4日
    84
  • datax(3): win环境cmd乱码「建议收藏」

    datax(3): win环境cmd乱码「建议收藏」通过前面两篇文章,大家应该已经可以安装成功datax,但是在win的cmd下竟然中文乱码。解决它!!!一,环境win10datax3.xcmdpy3.x二,现象运行python\xxx\datax.py\xxx\job.json后控制台乱码三,解决1,临时解决命令:chcp(更改该控制台的活动控制台代码页)过程:cmd下输入chcp65001改变当前代码页变为utf-8编码常用的编码及对应的码值(10进制):十进制码值 对应编码名称950 .

    2022年5月13日
    100
  • Scala之隐式转换「建议收藏」

    Scala之隐式转换「建议收藏」概述简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。隐式转换有四种常见的使用场景:将某一类型转换成预期类型类型增强与扩展模拟新的语法类型类语法隐式转换有新旧两种定义方法,旧的定义方法指是的“implictdef”形式,这是Scala2.10版本之前的写法,在Scala2.10版本之

    2022年10月11日
    2
  • shuffle洗牌算法java_洗牌算法shuffle[通俗易懂]

    洗牌算法1.背景阿里的面试的时候做的一道笔试题:题目:写一个方法,入参为自然数n(n>0),返回一个自然数数组,数组长度为n,元素为[1,n]之间,且每个元素不重复,数组中各元素顺序要求随机;实例1:输入:N=3输出:132实例2:输入:N=5输出:32514当时我的解法(写了两种方法):写的好烂,面完和面试官交流的时候面试官让我看下Collect…

    2022年4月7日
    43
  • AvalonDock学习总结

    AvalonDock学习总结介绍:借助AvalonDock可以开发出类似于VS2010的软件界面,实现可停靠布局。使用时需要Nugit中下载Extended.wpf.toolkit插件.在Xaml中需要应用命名空间xmlns:avalon=”http://schemas.xceed.com/wpf/xaml/avalondock”AvalonDock库提供了一些基本的类。DockingManger:管理停靠类。DockingManger中只允许包含一个LayoutRoot类DockingM…

    2022年7月20日
    16
  • linux chmod 755的含义

    linux chmod 755的含义chmod是Linux下设置文件权限的命令,后面的数字表示不同用户或用户组的权限。一般是三个数字:第一个数字表示文件所有者的权限第二个数字表示与文件所有者同属一个用户组的其他用户的权限第三个数字表示其它用户组的权限。 权限分为三种:读(r=4),写(w=2),执行(x=1) 。 综合起来还有可读可执行(rx=5=4+1)、可读可写(rw=6=4+2)、可读可写可执行(r

    2022年7月16日
    23

发表回复

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

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