线程的几种创建方式
- 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
}