android多线程

android多线程

上图是Android中实现多线程的主要方式,以及线程的控制流程。

1.最基本的方式是在需要的时候添加一个线程,但是这种方式不利于线程管理,容易造成内存泄漏。想象一下,你在活动中有一个新的线程来处理耗时的任务,任务结束后,你可以通过处理程序切换到UI线程来操作UI。这时你的Activity已经被销毁了,因为Thread还在运行,所以不会被销毁。另外,线程中有对Handler的引用,必然会导致内存泄漏和崩溃。

NewThread:可以复制Thread#run方法,也可以传递Runnable对象。缺点:缺乏统一管理,线程无法重用,会造成线程间的竞争,可能会占用过多的系统资源,导致死机或oom。

编写Thread的两种方法是classthreadrunnable:Thread(){ override fun run(){ Thread。sleep (10000)}}趣味测试thread () {thread {thread。睡眠(10000)}。start () ThreadRunable()。start()}2。在Android中,我们也将使用AsyncTask来构建我们自己的异步任务。但是Android中所有的AsyncTask都共享一个线程池,线程池的核心线程数为1,也就是说如果你多次调用AsyncTask.execute方法,你的任务直到前一个任务完成才会执行。Android不再推荐AsyncTask。

@Deprecatedpublic静态最终执行器SERIAL _ Executor = new SERIAL Executor();私有静态类SerialExecutor实现了Executor { final ArrayDeque & ltRunnable & gtmTasks = new ArrayDeque & ltRunnable & gt();可运行的mActivepublic synchronized void execute(final Runnable r){ mtasks . offer(new Runnable(){ public void run(){ try { r . run();} finally { schedule next();} } });if(MAC active = = null){ schedule next();} } protected synchronized void schedule next(){ if((MAC tive = mt asks . poll())!= null){ THREAD _ POOL _ executor . execute(MAC active);}}}使用AsyncTask有几种方法。

2.1.继承异步任务

类MyAsyncTask:async task & lt;String,Int,String & gt(){//这个方法在线程池中调用,异步任务的代码在这个方法中运行。参数表示运行异步任务传递的参数,覆盖资金后台(varargparams: string?):string {log.e(标签,线程。currentthread()。名称)用于(0中的进度..100){//传递任务进度发布进度(progress)} return & # 34;成功& # 34;}//UI线程上运行的参数代表异步任务传递的进度,override fun on progress update(vararg values:int?){ Log.e(标签,& # 34;进度${values},线程${Thread.currentThread()。name } & # 34)}//异步任务完成时,UI线程上运行的参数代表异步任务操作的结果,override fun onpostexecute(result:string?){ Log.e(标签,& # 34;结果${result},线程${Thread.currentThread()。name } & # 34)}}MyAsyncTask()。执行(& # 34;123") 2.2.直接调用execute方法来传递Runable对象。

对于(我在0..10){ async task . execute(Runnable { log . e(TAG,& # 34;对于invoke: ${Thread.currentThread()。name } time $ { system . current time millis()} & # 34;)thread.sleep (10000)}} 2.3。将任务直接添加到线程池中。

/* * *在0中并发执行任务*/for (ii…10) {asynctask。线程池执行者。execute (runnable {log.e (tag,& # 34;对于invoke: ${Thread.currentThread()。name } time $ { system . current time millis()} & # 34;)}} 2.4.第三种是并行执行,使用AsyncTask内部的线程池。

@Deprecatedpublic静态最终执行器THREAD _ POOL _ EXECUTORstatic { ThreadPoolExecutor ThreadPoolExecutor = new ThreadPoolExecutor(CORE _ POOL _ SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE_SECONDS,TimeUnit。秒,新同步队列& ltRunnable & gt()、sThreadFactory);threadpoolexecutor . setrejectedexecutionhandler(sRunOnSerialPolicy);THREAD _ POOL _ EXECUTOR = threadpool EXECUTOR;}3.使用句柄线程

HandlerThread内部维护一条消息,该消息循环遍历子线程,允许您将任务发送到子线程。

使用方法如下。我们需要先构建一个HandlerThread的实例,调用start方法启动内部循环。

之后,您需要创建一个处理程序并在HandlerThread的循环中传递,并在内部实现handleMessage方法来处理任务。

fun handler thread(){ val handler thread = handler thread(& # 34;处理程序_ _线程& # 34;)handlerThread.start() //传递的循环是ThreadHandlerValHandler = Object:Handler(Handler thread。looper){ Override FunHandleMessage(msg:message){ log . e(tag,& # 34;handler thread $ { thread . current thread()。name } & # 34)}}处理程序。sendmessage(1)} 4。IntentService执行任务后自动销毁任务,适用于一次性任务(已被放弃)。建议使用工作管理器。

/* * *任务执行后自动销毁,适用于一次性任务*/clasyIntentService:intent service(& # 34;MyIntentService & # 34){ override fun onHandleIntent(Intent:Intent?){ log . e(& # 34;MyIntentService & # 34, "Thread ${Thread.currentThread()。name } & # 34) }}5.使用线程池。

线程池是控制线程最常用的方法。它可以集中管理您的线程,重用线程,避免由于打开太多新线程而导致的内存不足。线程池的详细分析将在下一章中描述。

public thread pool executor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue & ltRunnable & gtWorkqueue,threadfactory threadfactory,rejectedexecutionhandler)是线程池的构造函数。

CorePoolSize是线程池中核心线程的数量,这些线程不会被回收。

maximumPoolSize是线程池中线程的最大数量,分为核心线程和非核心线程,两者之和为MaximumPoolSize。非核心线程将在任务执行一段时间后被释放。

KeepAliveTime非核心线程存在的时间。

非核心线程存在的时间单位。

WorkQueue任务队列,当所有核心线程都在处理任务时,将任务存储在任务队列中。只有当任务队列已满时,才会启动非核心线程。

ThreadFactory构建一个线程项目,一般在线程启动前处理一些操作。

处理程序拒绝该策略。当线程池关闭时(调用shutdonw),线程池中的线程数等于maximumPoolSize,当任务队列已满时会调用它。

主要方法

Void execute(Runnable run)//将任务提交给线程池进行调度。

Void shutdown()//关闭线程池,等待任务执行完成。

Void shutdownNow()//不等待任务完成就关闭线程池。

Int getTaskCount()//返回在线程池中找到的所有任务的数量(已完成任务+阻塞队列中的任务)。

Int getCompletedTaskCount()//返回线程池中已完成任务的数量。

Int getPoolSize()//返回线程池中创建的线程数。

Int getActiveCount()//返回当前运行的线程数。

void terminated()线程池终止时要执行的策略。

线程池有几种内置方式。

5.1.newFixedThreadPool使用固定数量的线程创建一个线程池。核心线程的数量等于核心线程的最大数量。

以这种方式创建的线程池如果不加以控制,将会导致内存溢出,因为它使用了未绑定的LinkedBlockingQueue。

创建一个固定线程数的线程池,public static executor service new fixed thread pool(int threads){ return new thread pool executor(threads,threads,0l,timeunit.mills,new linked blocking queue

public static ExecutorService newSingleThreadExecutor(){ return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit。毫秒,新建LinkedBlockingQueue & ltRunnable & gt()));}5.3.newCachedThreadPool创建一个线程池,没有核心线程,线程数量无限。因为使用了SynchronousQueue,所以不会存储任务,并且会为每个提交的任务创建一个新线程。当任务足够多的时候,也会造成内存溢出。

public static ExecutorService newCachedThreadPool(){ return new threadpool executor(0,Integer。MAX_VALUE,60L,时间单位。秒,新同步队列& ltRunnable & gt());}以上三种方法其实都不推荐。线程池的使用要根据使用场景合理安排核心线程和非核心线程。

作者:东土爷
链接:https://juejin.cn/post/7145002669155811364
来源:稀土掘金。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

发表回复

登录后才能评论