Android 线程和线程池核心技术-走进线程世界 (一)

🔥 走进线程世界 🔥

        安卓应用在运行时必然存在一个进程 , 进程中必然会存在一个线程 (我们称之为UI线程)。线程可以看着是进程的实体 , 也是CPU调度的基本单位 , 也是比较进程更小的独立运行的基本单位 。安卓中的线程可以分为两类 : 一类是UI线程 , 另外一类是工作线程 。引用工作线程的原因 : UI线程都是用来更新UI控件的 , 耗时任务也在UI线程中来执行 , 势必会引起UI线程的ANR , 可以说工作线程就是来分担UI线程的压力 多开工作线程并不会提高UI的流畅度 , UI线程和工作线程两者是存在竞争关系的。同样是线程都需要等待CPU分配时间片 , 才能够真正运行起来的 。

🔥 线程的分类 🔥 

异步任务执行的方式 (五种)

new Thread

AsyncTask (轻量级的异步任务执行工具)

HandlerThread (线程间可以通信且任务可直接运行)

IntentService

ThreadPoolExcutor (线程池)

线程的优先级 (设置线程优先级的两种方式)

线程完成创建后执行 start() 函数后并不是立刻执行得到调度的 , 线程的优先级越高获得CPU时间片的概率越大 , 那么该线程就能够越早得到调度 。

android.os.Process.setThreadPriority

java.lang.Thread.setPriority

线程的状态 ( 四种 )

sleep (暂时让出CPU的使用权) 

yeild (多个线程同步的场景)

join (线程之间顺序的场景)

wait-notify(notifyAll)

 🔥 线程之间通讯 🔥

子线程向主线程发送消息

主线程向自线程发送消息

🔥 线程安全 🔥 

关键字同步

        synchronized

        volatile

JUC工具

        Lock

                WriteLock

                ReadLock

                ReentrantLock

        Atomic

                AtomicInteger

                AtomicBoolean

                AtomicStampedReference

         Concurrent

                CountDownLatch

                CyclicBarrier

                Semaphore

并发容器

        CopyOnWriteArrayList

        ConcurrentHashMap

🔥 线程与进程 🔥 

一个进程至少包含一个线程

进程可以包含多个线程

进程在执行过程中拥有独立的内存空间 , 而线程运行在进程内

🔥 线程的几种创建方式 🔥 

new Thread

 可复写Thread 的run() 函数 。也可传递Runnable对象 , 更近灵活。

缺点 : 缺乏统一管理 , 可能无限制新建线程 , 相互之间竞争 , 及可能只用过多系统资源导致死机或oom

传递Runnable对象

Java

new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();

Kotlin

 Thread {

        }.start()

 重写Thread的 run() 函数

Java

 class MyThread extends Thread{
        @Override
        public void run() {
            super.run();
        }
    }


 new MyThread().start();

Kotlin

   internal class MyThread : Thread() {
        override fun run() {
            super.run()
        }
    }


MyThread().start()

 AsyncTask

轻量级的异步任务工具类 , 提供任务执行的进度回调给UI线程

场景 : 需要知道任务执行的进度 , 多个任务串行执行 。

缺点 : 生命周期和宿主的生命周期不同步 , 有可能发生内存泄露 (解决方案就是在创建AsyncTask类前面加上static关键字), 默认情况所有任务串行执行 。

 Java

MyAsyncTask asyncTask=new MyAsyncTask();
MyAsyncTask asyncTask2=new MyAsyncTask();
/// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
asyncTask.execute("execute MyAsyncTask one");
asyncTask2.execute("execute MyAsyncTask two");
/// 传递AsyncTask.THREAD_POOL_EXECUTOR参数可以做到并发执行 
/// 很多文章说会并发执行,但是跟串行没有区别(有待考证)
//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask one");
//asyncTask2.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask two");
class MyAsyncTask extends AsyncTask<String,Integer,String>{
        private static final String TAG="MyAsyncTask";
        @Override
        protected String doInBackground(String... params) {
            ///1、向onProgressUpdate()函数抛出执行UI的更显操作
             for (int i=0;i<10;i++){
                 publishProgress(i*10);
             }
             return params[0];
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            ///3、执行结果
            System.out.println(TAG+"result: "+result);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            ///2、此处执行UI的更新操作
            System.out.println(TAG+"onProgressUpdate: "+values[0].intValue());
        }
    }
I/System.out: MyAsyncTaskonProgressUpdate: 0
I/System.out: MyAsyncTaskonProgressUpdate: 10
I/System.out: MyAsyncTaskonProgressUpdate: 20
I/System.out: MyAsyncTaskonProgressUpdate: 30
I/System.out: MyAsyncTaskonProgressUpdate: 40
I/System.out: MyAsyncTaskonProgressUpdate: 50
I/System.out: MyAsyncTaskonProgressUpdate: 60
I/System.out: MyAsyncTaskonProgressUpdate: 70
I/System.out: MyAsyncTaskonProgressUpdate: 80
I/System.out: MyAsyncTaskonProgressUpdate: 90
I/System.out: MyAsyncTaskresult: execute MyAsyncTask one
I/System.out: MyAsyncTaskonProgressUpdate: 0
I/System.out: MyAsyncTaskonProgressUpdate: 10
I/System.out: MyAsyncTaskonProgressUpdate: 20
I/System.out: MyAsyncTaskonProgressUpdate: 30
I/System.out: MyAsyncTaskonProgressUpdate: 40
I/System.out: MyAsyncTaskonProgressUpdate: 50
I/System.out: MyAsyncTaskonProgressUpdate: 60
I/System.out: MyAsyncTaskonProgressUpdate: 70
I/System.out: MyAsyncTaskonProgressUpdate: 80
I/System.out: MyAsyncTaskonProgressUpdate: 90
I/System.out: MyAsyncTaskresult: execute MyAsyncTask two

Kotlin

val asyncTask: MyAsyncTask = MyAsyncTask()
val asyncTask2: MyAsyncTask = MyAsyncTask()
/// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
/// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
asyncTask.execute("execute MyAsyncTask one")
asyncTask2.execute("execute MyAsyncTask two")
/// 传递AsyncTask.THREAD_POOL_EXECUTOR参数可以做到并发执行
/// 很多文章说会并发执行,但是跟串行没有区别(有待考证)
//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask one");
//asyncTask2.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask two");
 internal class MyAsyncTask : AsyncTask<String?, Int?, String>() {
         override fun doInBackground(vararg params: String?): String? {
            ///1、向onProgressUpdate()函数抛出执行UI的更显操作
            for (i in 0..9) {
                publishProgress(i * 10)
            }
            return params[0]
        }

        override fun onPostExecute(result: String) {
            super.onPostExecute(result)
            ///3、执行结果
            println(TAG + "result: " + result)
        }

         override fun onProgressUpdate(vararg values: Int?) {
            super.onProgressUpdate(*values)
            ///2、此处执行UI的更新操作
            println(TAG + "onProgressUpdate: " + values[0])
        }

        companion object {
            private const val TAG = "MyAsyncTask"
        }

    }

 AsyncTask

串行和并行执行时 , 无需返回执行进度给UI的方式

Java 串行执行

以这种方式提交的任务,所有任务串行执行,即先来后到,但是如果其中有一条任务休眠了, 或者执行时间长 , 后面的任务都将被阻塞

 AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("任务一:"+i);
                }
            }
        });

        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("任务二:"+i);
                }
            }
        });

Kotlin 串行执行

AsyncTask.execute {
            for (i in 0..9) {
                println("任务一:$i")
            }
        }

        AsyncTask.execute {
            for (i in 0..9) {
                println("任务二:$i")
            }
        }

 Java 并行执行

使用 AsyncTask内置的THREAD_POOL_EXECUTOR 线程池并发执行

AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("任务一:"+i);
                }
            }
        });

        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("任务二:"+i);
                }
            }
        });
I/System.out: 任务二:0
I/System.out: 任务二:1
I/System.out: 任务二:2
I/System.out: 任务二:3
I/System.out: 任务二:4
I/System.out: 任务二:5
I/System.out: 任务二:6
I/System.out: 任务二:7
I/System.out: 任务二:8
I/System.out: 任务二:9
I/System.out: 任务一:0
I/System.out: 任务一:1
I/System.out: 任务一:2
I/System.out: 任务一:3
I/System.out: 任务一:4
I/System.out: 任务一:5
I/System.out: 任务一:6
I/System.out: 任务一:7
I/System.out: 任务一:8
I/System.out: 任务一:9

Kotlin 并行执行

使用 AsyncTask内置的THREAD_POOL_EXECUTOR 线程池并发执行

AsyncTask.THREAD_POOL_EXECUTOR.execute {
            for (i in 0..9) {
                println("任务一:$i")
            }
        }

        AsyncTask.THREAD_POOL_EXECUTOR.execute {
            for (i in 0..9) {
                println("任务二:$i")
            }
        }

HandlerThread 

适用于主线程和工作线程通信 , 适用于持续性任务 , 比如轮询的场景 , 所有任务串行执行

缺点 : 不会像普通线程一样主动销毁资源 , 会一直运行着 , 所以可能会造成内存泄露

Java

///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
///去轮询主线程里面的消息队列。
///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
/// 需要调用quitSafely()函数停止任务
HandlerThread thread=new HandlerThread("handler-thread");
thread.start();
///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
/// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
/// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
ThreadHandler handler=new ThreadHandler(thread.getLooper());
handler.sendEmptyMessage(1000);
///thread.quitSafely();
//定义成静态,防止内存泄漏
    static class ThreadHandler extends Handler{
        public ThreadHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            System.out.println("handleMessage: "+msg.what);
            System.out.println("handleMessage: "+Thread.currentThread().getName());
        }
    }
I/System.out: handleMessage: 1000
I/System.out: handleMessage: handler-thread

Kotlin

///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
///去轮询主线程里面的消息队列。
///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
/// 需要调用quitSafely()函数停止任务
///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
///去轮询主线程里面的消息队列。
///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
/// 需要调用quitSafely()函数停止任务
val thread = HandlerThread("handler-thread")
thread.start()
///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
/// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
/// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
/// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
/// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
val handler = JavaHandlerThreadActivity.ThreadHandler(thread.looper)
handler.sendEmptyMessage(1000)
///thread.quitSafely();
//定义成静态,防止内存泄漏
    internal class ThreadHandler(looper: Looper?) : Handler(looper!!) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            println("handleMessage: " + msg.what)
            println("handleMessage: " + Thread.currentThread().name)
        }
    }
I/System.out: handleMessage: 1000
I/System.out: handleMessage: handler-thread

 IntentService

IntentService拥有了Service的全部生命周期 , 包含了Service的全部特性 。与Service不同的是IntentService会创建一个线程来执行我们的耗时任务。

适用于我们的任务需要跨页面读取任务执行的进度结果 。比如后台上传图片, 批量操作数据库等 。任务执行完成后就会自我结束 , 所以不需要手动stopservice , 这是它跟service的区分。

Java

  class MyIntentService extends IntentService{
        /**
         * @param name
         * @deprecated
         */
        public MyIntentService(String name) {
            super(name);
        }

        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            int command=intent.getIntExtra("command",0);
        }

    }
startService(new Intent());

Kotlin

internal class MyIntentService
    /**
     * @param name
     */
    @Deprecated("") constructor(name: String?) : IntentService(name) {
        override fun onHandleIntent(intent: Intent?) {
            val command = intent!!.getIntExtra("command", 0)
        }
    }
startService(Intent())

 ThreadPoolExecutor

使用处理大量耗时较短的任务场景 。

Executors.newCachedThreadPool();//线程可复用线程池
Executors.newFixedThreadPool(0)//固定线程数量的线程池
Executors.newScheduledThreadPool(0)//可指定定时任务的线程池
Executors.newSingleThreadExecutor();// 线程数量为1的线程池

🔥 线程的优先级 🔥 

线程的优先级具有继承性 , 在某线程中创建的线程会继承此线程的优先级 。那么我们在UI线程中创建了线程 , 则线程的优先级和UI线程的优先级一样 , 平等和UI线程抢占CPU时间片资源。

JDK  Api , 限制了新设置的线程的优先级必须为[1~10] , 优先级priority的值越高 , 获取CPU时间片的概率越高。UI线程优先级为5

java.lang.Thread.setPriority(int newPriority)

Android Api ,  可以为线程设置更加精细的优先级 (-20~19) ,  优先级priority的值越低 , 获取 CPU时间片的概率越高 。UI线程优先级为-10 , 线程的优先级具有竞争性 , 所以会和我们的子线程进行竞争 。

android.os.Process.setThreadPriority(int newPriority)

setPriority 和  setThreadPriority 设置线程优先级的作用域是相互隔离的 。线程优化的时候需要我们间接性的设置线程的优先级 

AsyncTask设置了优先级

public class JavaTestPriorityActivity extends AppCompatActivity {

    private final static String TAG="JavaTestPriorityActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_java_test_priority3);

        Thread thread=new Thread();
        thread.start();
        int ui_proi= Process.getThreadPriority(0);
        int th_proi=thread.getPriority();

        System.out.println(TAG+" Process.getThreadPriority(0) :"+ui_proi);
        System.out.println(TAG+" thread.getPriority() :"+th_proi);
    }
}
I/System.out: JavaTestPriorityActivity Process.getThreadPriority(0) :-10
I/System.out: JavaTestPriorityActivity thread.getPriority() :5

案例 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

️ 邪神

你自己看着办,你喜欢打赏我就赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值