多线程在android中的使用_android 多线程下载是多个线程使用同一个连接m - CSDN
  • 1)为什么需要多线程处理? 解决耗时任务 文件IO、联网请求、数据库操作、RPC 提高并发能力 同一时间处理更多事情 防止ANR InputDispatching Timeout:输入事件分发超时5s(触摸或按键) Service Timeout:服务...

    写在前面:内容主要为黄岳钊老师视频分享课的学习笔记。


    1)为什么需要多线程处理?

    • 解决耗时任务
      文件IO、联网请求、数据库操作、RPC

    • 提高并发能力
      同一时间处理更多事情

    • 防止ANR
      InputDispatching Timeout:输入事件分发超时5s(触摸或按键)
      Service Timeout:服务20s内未执行完
      BroadcastQueue Timeout:前台广播10s内未执行完
      ContentProvider Timeout:内容提供者执行超时

    • 避免掉帧
      要达到每秒60帧,每帧必须16ms处理完


    2)使用多线程的几种姿势

    • Thread
      ① new Thread,重载run方法;
      ② 实现Runable接口,作为参数传给Thread。
    public static void main(String[] args){
            //Android中   UI线程的Id恒定为1
            System.out.println("UI Thread Id : "+Thread.currentThread().getId());
    
            new Thread(){
                @Override
                public void run() {
                    // TODO: 2016/12/2
    
                    System.out.println("run in thread "+Thread.currentThread().getId());
                }
            }.start();
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    // TODO: 2016/12/2
                    System.out.println("run in thread "+Thread.currentThread().getId());
                }
            };
    
            new Thread(runnable).start();
        }

    这里写图片描述

    • AsyncTask

    android特有的轻量级异步任务类,它可以在线程池中执行后台任务,然后把执行进度和结果传递给主线程中更新UI。但不适合特别耗时的后台任务。

    (android特有,为便于更新UI,由google推出)

    public class MyTask extends AsyncTask<String,Integer,String> {
    
        String TAG = "haha";
    
        @Override
        protected void onPreExecute() {
            // TODO: 2016/12/2
            Log.d(TAG,"onPreExecute run in thread "+Thread.currentThread().getId());
        }
    
        //只有这个方法在后台执行,其他方法都在UI线程
        @Override
        protected String doInBackground(String... params) {
            // TODO: 2016/12/2
            Log.d(TAG,"doInBackground run in thread "+Thread.currentThread().getId());
            //传入的参数和execute中传入参数相同
            Log.d(TAG,"input param "+params[0]);
    
            //此方法将回调onProgressUpdate 用于进度更新
            publishProgress(5);
            //此return的信息将传递到onPostExecute
            return "task done!";
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
            // TODO: 2016/12/2
            Log.d(TAG,"onProgressUpdate run in thread "+Thread.currentThread().getId());
    
            Log.d(TAG,"update progress "+values[0]);
    
        }
    
        @Override
        protected void onPostExecute(String s) {
            // TODO: 2016/12/2
            Log.d(TAG,"onPostExecute run in thread "+Thread.currentThread().getId());
            Log.d(TAG,"onPostExecute input "+s);
    
        }
    
    }
    

    这里写图片描述

    分析:AsyncTask只有doInBackground 在子线程中执行,其他都是在UI线程。

    使用注意点:

    1)想象一种情况:在一个Activity页面,如果发起了AsyncTask任务,然后页面离开/销毁了,此时如果doInBackground没执行完,会有什么问题?
    首先,AsyncTask白白消耗资源,结果已经用不上了,因为UI也不在;

    2)那么如何优雅的终止AsyncTask呢?
    鉴于以上的问题,一般我们要在Activity onDestory的时候cancel掉AsyncTask任务。

    3)关于cancel()方法
    cancel()方法并非是直接停止Asynctask后台线程,而是发送一个停止线程的状态位,
    因而需要在doInBackground 不断的检查此状态位。
    如:if(isCancelled()) return null; // Task被取消了,马上退出

    • HandlerThread

    HandlerThread实际上是一个带有Looper的Thread,从而可向子线程传递消息。

    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //HandlerThread 其实就是一个带有Looper的Thread
            HandlerThread handlerThread = new HandlerThread("handler-thread");
            handlerThread.start();
    
            Log.d(TAG,"handlerthread id :"+handlerThread.getId());
    
            //用handlerThread的looper生成handler  用于向子线程中发送消息、runnable 等
            Handler handler = new Handler(handlerThread.getLooper()){
                @Override
                public void handleMessage(Message msg) {
                    Log.d(TAG,"handleMessage received in thread "+Thread.currentThread().getId());
    
                    Log.d(TAG,"received message is "+msg.obj);
                }
            };//必须先start thread
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"this runnable run in thread "+Thread.currentThread().getId());
                }
            };
            //使runnable在子线程(即handlerThread线程执行)
            handler.post(runnable);
            //此消息发送至handlerThread线程
            Message message = new Message();
            message.obj = "test message";
            handler.sendMessage(message);
        }

    这里写图片描述

    • ExecutorService

    首先来看下java.util.concurrent包下关于并发编程的几个重要类和接口:Executor,Executors、ExecutorService。

    Executor(执行器):
    如下,是一个接口,提供了execute()方法,用于执行任务,而不用显式的创建线程(使用其内部的线程池来完成操作)。
    其最常用的子接口ExecutorService,扩展了shutdown()、submit()等方法,用于管理终止任务。

    这里写图片描述
    ExecutorService:
    shutdown:完成已提交的任务后(调用后不能再提交新任务,且可以等待已提交任务执行完),关闭ExecutorService以回收资源。
    submit:返回Future对象,用于取消执行或等待完成。
    invokeAll:用于批量执行。

    这里写图片描述
    Executors:
    主要用于提供线程池相关的操作,返回Executor执行器。
    这里写图片描述

    再来看几种不同的线程池:FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadPool。

    FixedThreadPool:
    通过Executors.newFixedThreadPool()创建,是一种线程数量固定的线程池。线程并不会被回收,除非线程池被关闭。当所有线程处于活动状态,新任务会被阻塞,直至有线程可用。
    适于线程数固定。

    CachedThreadPool:
    通过Executors.newCachedThreadPool()创建,线程数量不定。只有非核心线程,最大线程数为Integer.MAX_VALUE。
    空闲线程有超时机制,时长为60s,超过60s闲置线程会被回收。
    当没有空闲线程时,对新任务会创建新线程,从而保证所有任务立即被执行。
    适于执行大量且耗时较短的任务,线程数按需创建,用完回收。

     Runnable runnable2 = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"runnable2 run in thread "+Thread.currentThread().getId());
    
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.d(TAG,"runnable2 is interrupted");
                    }
                    Log.d(TAG,"任务完成!");
    
                }
            };
    
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.execute(runnable2);
            executorService.execute(runnable2);
            try {
                //休眠10s   前面的任务都执行完  且线程都没有被回收,新添加的任务将使用现有的空闲线程
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //将复用前面的两个空闲线程
            executorService.execute(runnable2);
            executorService.execute(runnable2);
            try {
                //休眠70s  空闲线程被回收,新添加的任务将启动新线程
                TimeUnit.SECONDS.sleep(70);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //所有的空闲线程已空闲60s而被回收  因而新添加的任务将创建新线程
            executorService.execute(runnable2);
            executorService.shutdown();

    这里写图片描述

    ScheduledThreadPool:
    通过Executors.newScheduledThreadPool()创建,核心数量固定且非核心线程数量无限制,当非核心线程闲置时立即被回收。
    适于执行定时任务和固定周期的重复任务。

    Runnable runnable2 = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"runnable2 run in thread "+Thread.currentThread().getId());
    
                    try {
                        //睡眠1min  为了便于观察结果
                        TimeUnit.SECONDS.sleep(60);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.d(TAG,"runnable2 is interrupted");
                    }
                    Log.d(TAG,"任务完成!");
    
                }
            };
    
            ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
            scheduledExecutorService.schedule(runnable2,1,TimeUnit.SECONDS);
            scheduledExecutorService.schedule(runnable2,1,TimeUnit.SECONDS);
            //创建的时候核心线程数为2  因此任务数目大于2时会等待前面的任务执行完才会开始执行新任务
            scheduledExecutorService.schedule(runnable2,1,TimeUnit.SECONDS);
    
            scheduledExecutorService.shutdown();

    这里写图片描述
    (注意观察任务完成的时间和线程id)

    SingleThreadPool:
    通过 Executors.newSingleThreadExecutor()创建,只有一个核心线程,因而所有任务顺序执行,因而不用处理线程同步问题。

     Runnable runnable1 = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"runnable1 run in thread "+Thread.currentThread().getId());
                }
            };
    
            Runnable runnable2 = new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG,"runnable2 run in thread "+Thread.currentThread().getId());
    
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.d(TAG,"runnable2 is interrupted");
                    }
                }
            };
    
    
            ExecutorService singleThreadTool = Executors.newSingleThreadExecutor();
    
            singleThreadTool.execute(runnable1);
            singleThreadTool.execute(runnable1);
    
            Future future = singleThreadTool.submit(runnable2);
    
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //停止runnable2
            future.cancel(true);
            //关闭线程池
            singleThreadTool.shutdown();
            //此任务不会被执行
            singleThreadTool.submit(runnable1);

    这里写图片描述

    • IntentService

    IntentService是一种特殊的Service,继承自Service且是一个抽象类。其子类必须实现onHandleIntent方法。
    IntentService底层通过HandlerThread实现。onHandleIntent方法在后台运行。
    由于IntentService是服务,不容易被系统杀死,适于执行高优先级的后台任务。


    3)使用多线程的公共问题

    • 生命周期
      运行时间长,不受UI生命周期限制,引用外部UI类、Activity容易导致内存泄漏。
    • UI操作
    • 通常不能直接操作UI,需要配合Handler。
    • 线程同步问题

    4)适用场景

    • Thread
      默认优先级与创建时所在线程相同,适合单次耗时任务,执行完自己会结束线程。
    • HandlerThread
      默认优先级与UI线程同,使用过多会导致UI卡顿;
      不使用时需手动调用HandlerThread.quit()退出。

    • AsyncTask
      本质是对ThreadPoolExecutor和FutureTask的封装,默认为后台线程优先级。
      提供了取消、进度通知、修改UI的能力,但不易使用。
      创建数量超过128个,会抛出异常。
      兼容性:1.6到2.x并发执行,3.0起串行执行。4.1之前首次使用必须要在UI线程创建。

    • ExecutorService
      优先级为默认优先级,不使用时需调用shutdown回收线程池。

    • IntentService
      不依赖UI,适于后台运行,执行完任务自动退出。


    5)推荐的多线程使用方式

    • 普通场景,要求高并发
      Executors.newFixedThreadPool()高复用
      Executors.newCachedThreadPool()低延迟

    • 需要顺序执行
      使用HandlerThread

    • 需要后台执行
      IntentService
    展开全文
  • Android多线程方式

    2018-03-26 22:58:22
    在Android开发经常会使用多线程,这里主要是总结Android开发常见的多线程实现方式,以及这些多线程实现方式的一些特点 多线程实现方式主要有: 实现Thread的run()方法或者实现Runable接口 HandlerThread ...

    1、前言

    在Android开发中经常会使用到多线程,这里主要是总结Android开发中常见的多线程实现方式,以及这些多线程实现方式的一些特点
    多线程实现方式主要有:

    • 实现Thread的run()方法或者实现Runable接口
    • HandlerThread
    • AsyncTask
    • LoaderManager

    2、Thread方式

    一般使用异步操作最常见的一种方式,我们可以继承Thread,并重写run()方法,如下所示:

    Thread syncTask = new Thread() {
        @Override
        public void run() {
            // 执行耗时操作
        }
    };
    
    syncTask.start();

    还有另外一种启动线程的方式,即在创建Thread对象时,传入一个实现了Runable接口的对象,如下所示:

    Thread syncTask = new Thread(new Runnable() {
        @Override
        public void run() {
            // 执行耗时操作
        }
    });
    
    syncTask.start();

    Thread类中有几个方法的作用有些模糊,这里给出说明:

    • interrupt( ):
      我们一般会使用该方法中断线程的执行,但该方法并不会中断线程,它的作用只是设置一个中断标志位,我们还得在run( )方法中判断这个标志位,并决定是否继续执行,通过这样的方式来达到中断的效果。 但该方法根据线程状态的不同,会有不同的结果。结果如下:
      1. 当线程由于调用wait( )、join( )、sleep( )而阻塞时,中断标志位将会被清空,并接收到InterruptedException异常。
      2. 当线程由于正在进行InterruptibleChannel类型的I/O操作而阻塞时,中断标志位将会置位,并接收到ClosedByInterruptException异常(I/O流也会自动关闭)
      3. 当线程由于进行Selector操作而阻塞时,中断标志位将会置位,但不会接收到异常

    interrupted( )和isInterrupted( )的区别:
    两个方法都是判断当前线程的中断标志位是否被置位,但调用interrupted( )方法后,中断标志位将会重置,而isInterrupted()不会被重置。

    • join( )和sleep( )的区别:两个方法都会让线程暂停执行

    join()方法是让出执行资源(如:CPU时间片),使得其它线程可以获得执行的资源。所以调用join()方法会使进入阻塞状态,该线程被唤醒后会进入runable状态,等待下一个时间片的到来才能再次执行。
    sleep( )不会让出资源,只是处于睡眠状态(类似只执行空操作)。调用sleep()方法会使进入等待状态,当等待时间到后,如果还在时间片内,则直接进入运行状态,否则进入runable状态,等待下个时间片。

    3、HandlerThread

    有些需求需要子线程不断的从一个消息队列中取出消息,并进行处理,处理完毕以后继续取出下一个处理。对于这个需求我们可以使用第一种方式,实现一个Thread对象,并创建一个消息队列,在Thread对象的run方法中不断的从消息队列中取出消息进行处理。多以该线程的这些特点有点像一个Looper线程,我们可复用Handler机制提供的消息队列MessageQueue,而无需自己重新创建。
    HandlerThread的内部实现机制很简单,在创建新的线程后,使该线程成为一个Looper线程,让该线程不断的从MessageQueue取出消息并处理。我们看一下HandlerThread的实现:

    public class HandlerThread extends Thread {
        int mPriority;
        Looper mLooper;
    
        /**
        * Constructs a HandlerThread.
        */
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
    
        @Override
        public void run() {
            // 要想让某个线程成为Looper线程,先调用Looper.prepare()为该线程创建一个Looper对象,并初始化MessageQueue对象
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            // 调用Looper.loop(),让该线程的Looper实例循环从MessageQueue中取出Message进行处理
            Looper.loop();
        }
    }

    4、AsyncTask

    这是我们最经常使用的一种异步方式,在前面的两种多线程方式中,如果在子线程中进行了耗时的处理操作(如:网络请求、读写数据库等),当操作完毕后,我们需要更新UI上的显示状态,但在Android开发中我们是不能在子线程中更新UI界面的,所以还得在子线程中发送一个通知到主线程,让主线程去更新UI。这样的操作流程有些复杂,且都是重复性的工作。所以Android sdk中为我们抽象出AsyncTask这个类。

    public class CustomAsyncTask extends AsyncTask<String, Integer, String> {
        @Override
        protected void onPreExecute() {
            // 在开始执行异步操作前回调,该方法在主线程中执行
        }
    
        @Override
        protected String doInBackground(String... strings) {
            // 在该方法中进行异步操作,参数strings是在启动异步任务时execute(...)传递进来的
            // 该异步任务放回的结果类型为String
            return null;
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
            // 该方法用户通知用户doInBackground()方法的处理进度,在主线程中被回调,所以可在该方法中更新UI
            // 参数values用于指示处理进度
        }
    
        @Override
        protected void onPostExecute(String result) {
            // 该方法是在异步操作doInBackground()处理完毕后回调,参数result是doInBackground()的处理结果
            // 该方法在主线程中被回调,可直接更新UI
        }
    
        @Override
        protected void onCancelled(String result) {
            super.onCancelled(result);
    
            // 当调用cancel(boolean), 则在doInBackground()完成后回调该方法
            // 注意: 参数result可能为null,
        }
    }

    AsyncTask的内部使用了两个线程池,我们大概看一下AsyncTask的内部实现

    // 顺序执行任务的线程池,注意这个线程池是静态的,每个AsyncTask对象共用这个线程池
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    
    // 我们启动异步任务的三个方法,都是向SerialExecutor.execute(runable)传递一个runable对象
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        ...
        exec.execute(mFuture);
        ...
        return this;
    }
    
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
    

    看一下SerialExecutor的实现

    private static class SerialExecutor implements Executor {
        // 存储待执行的异步任务
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
    
        public synchronized void execute(final Runnable r) {
            // 其实并没有马上执行,而是添加到队列mTasks中, 进行一个排队
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        // 一个任务执行完后,再执行下一个
                        scheduleNext();
                    }
                }
            });
    
            // 当前没有异步任务执行时,启动开始执行
            if (mActive == null) {
                scheduleNext();
            }
        }
    
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                // 使用另外一个线程池分配线程,并执行任务
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    

    所以在使用AsyncTask执行异步操作时,会先在SerialExecutor进行一个顺序排队, 后再用ThreadPoolExcutor线程池为你分配一个线程并执行。而整个应用的AsyncTask任务都在排同一条队,有可能等待排队的任务很多,所以一般不会使用AsyncTask执行一些优先级比较高的异步任务。
    当然我们是可以跳过不需要进行排队,直接就通过线程池分配一个线程并执行异步任务,但需要注意同时执行太多的异步任务,会影响用户体验,我想Google就是为了限制同时创建太多的线程才会采用一个排队机制的

    /** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    该方法是隐藏,但可使用反射,设置一个线程池。

    5、Loader&LoaderManager

    上面三种异步方式都可以用来加载一些耗时的数据,但有时我们加载数据的过程与Activity、Fragment的生命息息相关的。所以在使用上面说的那几种异步方式进行异步数据加载时,是需要去考虑Activity(Fragment)的生命周期是处于哪个阶段的。于是Android在Android 3.0以后引入了LoaderManager,主要用于执行一些耗时的异步数据加载操作,并根据Activity生命周期对异步处理进行调整,LoaderManager可以解决的问题包括:

    1. 加载的数据有变化时,会自动通知我们,而不自己监控数据的变化情况,如:用CursorLoader来加载数据库数据,当数据库数据有变化时,可是个展示变化的数据
    2. 数据的请求处理时机会结合Activity和Fragment的生命周期进行调整,如:若Acivity销毁了,那就不会再去请求新的数据

    使用该方法加载数据涉及到两个类重要的类,Loader和LoaderManager:

    Loader:该类用于数据的加载 ,类型参数D用于指定Loader加载的数据类型

    public class Loader<D> {
    }

    一般我们不直接继承Loader,而是继承AsyncTaskLoader,因为Loader的加载工作并不是在异步线程中。而AsyncTaskLoader实现了异步线程,加载流程在子线程中执行。注意:对该类的调用应该在主线程中完成。

    LoaderManager:
    LoaderManager用于管理与Activity和Fragment关联的Loader实例,LoaderManager负责根据的Activity的生命周期对Loader的数据加载器进行调度,所以这里分工明确,Loader负责数据加载逻辑,LoaderManager
    负责Loader的调度,开发者只需要自定义自己的Loader,实现数据的加载逻辑,而不再关注数据加载时由于Activity销毁引发的问题。

    注意:其实AsyncTaskLoader内部实现异步的方式是使用AsyncTask完成的,上面我们说过AsyncTask的内部是有一个排队机制,但AsyncTaskLoader内部使用AsyncTask进行数据异步加载时,异步任务并不进行排队。而直接又线程池分配新线程来执行。

    6、总结

    我们来总结一下异步处理的方式,以及每种处理方式适合什么样的场景

    • 直接使用Thread实现方式,这种方式简单,但不是很优雅。适合数量很少(偶尔一两次)的异步任务,但要处理的异步任务很多的话,使用该方式会导致创建大量的线程,这会影响用户交互。
    • HandlerThread,这种方式适合子线程有序的执行异步操作,异步任务的执行一个接着一个。
    • AsyncTask, 通常用于耗时的异步处理,且时效性要求不是非常高的那种异步操作。如果时效性要求非常高的操作,不建议使用这个方式,因为AsyncTask的默认实现是有内部排队机制,且是整个应用的AsyncTask的任务进行排队,所以不能保证异步任务能很快的被执行。
    • LoaderManager,当请求处理时机需要根据Activity的生命周期进行调整,或需要时刻监测数据的变化,那LoaderManager是很不错的解决方案。
    展开全文
  • 多线程的应用在Android开发是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 了解Android多线程实现方式前,需了解...

    前言

    • 多线程的应用在Android开发中是非常常见的,常用方法主要有:
      在这里插入图片描述

    • 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。


    目录

    在这里插入图片描述


    1. 多线程基础知识


    2. Android多线程实现方式

    Android多线程实现方式包括:
    在这里插入图片描述

    下面我会对每一个Android多线程实现方式进行详细说明。


    3. 基础使用

    Android多线程实现的基础使用包括:

    • 继承Thread类
    • 实现Runnable接口
    • Handler

    3.1 继承Thread类

    3.2 实现Runnable接口

    3.3 Handler

    HandlerAndroid多线程实现中非常常见 & 重要,所以大家务必要掌握。


    4. 复合使用

    Android多线程实现的复合使用包括:

    • AsyncTask
    • HandlerThread
    • IntentService

    称为”复用“的主要原因是:这3种方式的本质原理都是Android多线程基础实现(继承Thread类、实现Runnable接口、Handler)的组合实现。下面,我将详细讲解。

    4.1 AsyncTask

    4.2 HandlerThread

    • 简介
      在这里插入图片描述

    具体请看文章:

    4.3 IntentService


    5. 高级使用

    Android多线程的高级使用主要是线程池(ThreadPool)。

    5.1 简介

    在这里插入图片描述

    5.2 具体使用 & 工作原理

    Android多线程:线程池ThreadPool 全面解析


    6. 对比

    下面,将对比各种多线程实现方式,包括原理、功能 & 应用场景。
    在这里插入图片描述


    7. 其他

    7.1 线程同步:Synchronized关键字

    在这里插入图片描述

    具体请看文章:Java:手把手教你全面学习神秘的Synchronized关键字

    7.2 线程变量:ThreadLocal

    在这里插入图片描述

    具体请看文章:Java多线程:带你了解神秘的线程变量 ThreadLocal


    8. 总结

    • 本文主要全面介绍了Android中所有多线程的实现方式
    • 接下来,我会继续讲解Android开发中的其他知识,感兴趣的同学可以继续关注本人CSDN技术博客

    请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

    展开全文
  • android开发经验的人都知道,凡是耗时的操作不要放在UI线程种执行,否则会引起ANR错误。所以,如果要执行耗时的操作,我们需要另起线程执行。 通常情况新线程执行完耗时... android给我们提供了几种的多线程...

          有android开发经验的人都知道,凡是耗时的操作不要放在UI线程种执行,否则会引起ANR错误。所以,如果要执行耗时的操作,我们需要另起线程执行。

            通常情况在新线程执行完耗时操作以后,常常是要把结果反馈给UI界面,让UI线程更新界面。然而在android里面,UI线程不是线程安全的,所以不能在非UI线程里面更新界面。

             android给我们提供了几种的多线程的实现方式:

    1. Handler+Thread     

    优缺点

    1. Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了
    2. 处理单个异步任务代码略显多

    适用范围

    多个异步任务的更新UI

    2. AsyncTask

    优缺点
    1. 处理单个异步任务简单,可以获取到异步任务的进度
    2. 可以通过cancel方法取消还没执行完的AsyncTask
    3. 处理多个异步任务代码显得较多
    
    适用范围
    1. 单个异步任务的处理
    

    3. ThreadPoolExecutor

    适用范围
    1. 批处理任务

    4. IntentService

    特点
    1. 一个可以处理异步任务的简单Service

    展开全文
  • Android 线程

    2018-11-29 12:18:47
     线程在Android中是一个很重要的概念,从用途上来说,Android中线程可以分为主线程和子线程,主线程主要用来处理和界面相关的事,比如界面绘制和响应用户的操作,为了确保用户体验,主线程必须确保其响应速度,...
  • Android 多线程详解

    2017-03-21 20:18:50
    Android 多线程详解 一.多线程介绍 学习多线程之前我们首先要了解几个与多线程有关的概念。 进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程的程序,并且...
  • Android多线程(Handler篇)

    2019-09-04 18:15:58
    由于Android中的耗时操作不能放入主线程中,所以实现多线程是必须的。今天的主角是Handler,本文将从使用及源码来分析探索其奥秘。 使用 步骤: 创建Handler对象,实现handlMessage()方法 创建...
  • 今天来唠唠JNI关于多线程多线程,即多个线程同时工作,多线程的问题比较复杂,实际情况下可能会面临众多的问题。JNI也提供了一系列函数帮助我们完成多线程交互。博客内容大致分为如下:  1. 同步代码块 ...
  • Android 开发中多线程的必要性 理解 Android 多线程 MessageQueue Looper Handler HandlerThread Android 为什么只允许主线程更新 UI Android 系统为了避免过度复杂的线程安全问题特地规定只允许主线程更新 ...
  • ——Android中高级技术免费培训QQ群(118949422)第三期专题培训 本期的多线程主题与Android相关,侧重讲解在Android中如何用好多线程,需要你有Java的多线程基础。 首先我们思考几个问题,Android应用中为什么要...
  • 在Android 多线程中要注意的一点是, 在多线程中不能够更新界面的控件, 因为控件的更新只能由主线程来完成。  但是我们可以通过Handler 这个对象来对主线程的控件进行更新。  在多线程中如果想更新主线程的...
  • 服务学习服务之前必须先清楚多线程的问题。Android中多线程主要是为了操作一些耗时的工作,防止其将主程序进行阻塞。...Android与Java多线程不同点:1.Android中的更新UI必须主线程中进行,否则抛出异常。
  • 最近看到一篇讲解Android线程及其使用的文章,比较详细,此分享出来,感谢原作者的分享。 ----------------------------- 来源:http://android.jobbole.com/82440/ --------------------------------------- ...
  • 也可以用多线程下载,我们这里是java中写一个测试,其实android中的实现和java是一样的,学会了java就知道怎么在android中实现了,废话不多说了,怎么实现 多线程多线程的原理是什么样的,现在我们来学习一下。...
  • 本篇文章主要目的为总结 覆盖80%场景的20% Android端并发所需基础知识和应用。 Android 端应用主要使用 Java 语言...讨论并发其实就是讨论多线程。 而并发这个编程主题长久地被人拎出来讨论的原因,被前人们总结...
  • Android NDK C++中的多线程 前言 我们都知道Android是基于Linux内核的...所以我们在Android中使用C/C++线程也就转到 了使用POSIX线程库。他们都头文件“pthread.h”中。 函数相关 1、pthread_t: 用于声明...
  • 多线程的应用在Android开发是非常常见的,常用方法主要有: 继承Thread类 实现Runnable接口 Handler AsyncTask HandlerThread 今天,我将全面解析多线程其中一种常见用法:HandlerThread 由于本文涉及多线程...
  • Android可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;前者只要继承了Thread类同时覆写了本类的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。
  • 对于多线程,大家应该很熟悉。但是,大家了解线程池吗? 今天,我将带大家全部学习关于线程池的所有知识。 目录 1. 简介 2. 工作原理 2.1 核心参数 线程池有6个核心参数,具体如下 ...
  • 当然我们实际的Android项目需求也是如此,很多的业务需求都通过多线程及异步任务以便用户能够在使用App得到优秀的体验。而很多App在使用过程出现各种莫名其妙的问题,多是由于开发人员使用多线程不当造成的...
1 2 3 4 5 ... 20
收藏数 201,680
精华内容 80,672
关键字:

多线程在android中的使用