重新认识Android中的线程

线程的几种创建方式

  • new Thread:可复写Thread#run方法。也可以传递Runnable对象,更加灵活。
  • 缺点:缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统的资源导致死机或oom。
go 复制代码
 new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        }).start();
        
        class MyThread extends Thread{
            @Override
            public void run() {
                super.run();
            }
        }
        new MyThread().start();
  • AsyncTask,轻量级的异步任务工具类,提供任务执行的进度回调给UI线程
  • 场景:需要知晓任务执行的进度,多个任务串行执行
  • 缺点:生命周期和宿主的生命周期不同步,有可能发生内存泄漏(解决方案:将AsyncTask定义为静态内部类)
go 复制代码
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

public class ConcurrentTest {
    public static void test(Context context){
        class MyAsyncTask extends AsyncTask<String,Integer,String> {

            @Override
            protected String doInBackground(String... strings) {
                for (int i=0;i<10;i++){
                    publishProgress(i*10);
                }
                return strings[0];
            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                Log.e("hzulwy","onPostExecute: "+s);//输出:execute myAsyncTask
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                Log.e("hzulwy","onProgressUpdate: "+values[0]);//输出:10-90
            }
        }

        //适用于需要知道任务执行进度并更新UI的场景
        MyAsyncTask myAsyncTask = new MyAsyncTask();
        //默认串行
        myAsyncTask.execute("execute myAsyncTask");
        //并发执行
        myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"execute myAsyncTask");

        //以这种方式提交的任务,所有任务串行执行,即先来后到,但是如果其中有一条任务休眠了,或者执行时间过长,后面的任务将被阻塞
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                Log.e("hzulwy","run:AsyncTask.execute");
            }
        });

        //适用于并发任务执行
        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                Log.e("hzulwy","run: THREAD_POOL_EXECUTOR AsyncTask.execute");
            }
        });
    }
}
  • HandlerThread:适用于主线程需要和工作线程通信,适用于持续性任务,比如轮询的场景,所有任务串行执行。
  • 缺点:不会像普通线程一样主动销毁资源,会一直运行着,所以可能会造成内存泄漏 ,需要程序员手动释放
go 复制代码
public class ConcurrentTest {
    private static final int MSG_WHAT_1 = 1;

    public static void test1(){
        HandlerThread handlerThread = new HandlerThread("handler-thread");
        handlerThread.start();
        handlerThread.quitSafely();//在适当的地方释放资源
        
        MyHandler myHandler = new MyHandler(handlerThread.getLooper());
        myHandler.sendEmptyMessage(MSG_WHAT_1);
    }

    static class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Log.e("hzulwy","handleMessage: "+msg.what);//输出:1
            Log.e("hzulwy","handleMessage: "+Thread.currentThread().getName());//输出:handler-thread
        }
    }
}
  • IntentService:适用于我们的任务需要跨页面读取任务执行的进度,结果。比如后台上传图片,批量操作数据库等。任务执行完成后,就会自我结束,所以不需要手动stopservice,这是它与service的区分。IntentService包含了service的全部特色。
go 复制代码
    class MyIntentService extends IntentService{

        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            int command = intent.getIntExtra("command",0);
            //...
            
        }
        context.startService(new Intent());
    }
  • ThreadPoolExecutor:适用于快速处理大量耗时较短的任务场景(使用最广泛)
go 复制代码
        Executors.newCachedThreadPool();//线程可复用线程池
        Executors.newFixedThreadPool(1);//固定线程数量的线程池
        Executors.newScheduledThreadPool(1);//指定定时任务的线程池
        Executors.newSingleThreadExecutor();//线程数量为1的线程池

线程的优先级

go 复制代码
        Thread thread = new Thread();
        thread.start();
        
        int ui_proi = Process.getThreadPriority(0);
        int th_proi = thread.getPriority();
        
        //输出结果
        ui_proi =5;
        th_proi = 5;
  • 线程的优先级具有继承性,在某线程中创建的线程会继承此线程的优先级。那么我们在UI线程中创建了线程,则线程优先级是和UI线程优先级一样,平等的和UI线程抢占CPU时间片资源。
  • JDK api,限制了新设置的线程的优先级必须为[1~10],优先级priority的值越高,获取cpu时间片的概率越高。UI线程的优先级为5。使用这种方式来设置优先级对线程影响的概率并不大。
  • Android api,可以为线程设置更加精细的优先级(-20~19),优先级的值越低,获取CPU时间片的概率越高。UI线程优先级为-10。推荐使用,影响较大,而且与JDK的方式设置线程优先级互不影响。

Process.setThreadPriority(-10);

线程的几种状态与常用方法



go 复制代码
//需要保证wait-notify方法的调用顺序,即先wait后notify,否则会有假死的情况
 private volatile boolean hasNotify = false;
    final Object object = new Object();
    public void test2(){

        Thread thread1 = new Thread(new Runnable1());
        Thread thread2 = new Thread(new Runnable2());

        thread1.start();
        thread2.start();
    }

    class Runnable1 implements Runnable{
        @Override
        public void run() {
            Log.e("hzulwy","run:thread1 start");
            synchronized (object){
                try {
                    if(!hasNotify){//规避假死情况
                        object.wait(1000);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Log.e("hzulwy","run:thread1 end");
        }
    }

    class Runnable2 implements Runnable{
        @Override
        public void run() {
            Log.e("hzulwy","run:thread2 start");
            synchronized (object){
                object.notify();
                hasNotify = true;
            }
            Log.e("hzulwy","run:thread2 end");
        }
    }
go 复制代码
    public void test2(){
    //一个线程需要等待另一个线程执行完才能继续的场景
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("hzulwy","run: 1"+System.currentTimeMillis());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.e("hzulwy","run: 2"+System.currentTimeMillis());
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //等thread执行完成后才会执行下面的日志
        Log.e("hzulwy","test: 3"+System.currentTimeMillis());
        
        //输出结果:
        //run: 1
        //run: 2
        //test: 3
    }
相关推荐
恋猫de小郭1 小时前
你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解
android·前端·flutter
城东米粉儿3 小时前
Android Glide 笔记
android
城东米粉儿3 小时前
Android TheRouter 笔记
android
城东米粉儿9 小时前
Android AIDL 笔记
android
城东米粉儿9 小时前
Android 进程间传递大数据 笔记
android
城东米粉儿10 小时前
Android KMP 笔记
android
冬奇Lab11 小时前
WMS核心机制:窗口管理与层级控制深度解析
android·源码阅读
松仔log12 小时前
JetPack——Paging
android·rxjava
城东米粉儿12 小时前
Android Kotlin DSL 笔记
android