安卓应用在运行时必然存在一个进程 , 进程中必然会存在一个线程 (我们称之为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{ 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 twoKotlin
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() { 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: 任务一:9Kotlin 并行执行
使用 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-threadKotlin
///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