两种基本创建方式
- 继承Thread类,覆写run方法。
- 通过实现Runnable接口,或继承自Thread类,覆写run方法。
1.public class MainActivity extends AppCompatActivity {
ActivityMainBinding activityMainBinding;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
//子线程的创建
ThreadTaskDemo1 threadTask1 = new ThreadTaskDemo1();
threadTask1.setName("task-1");
threadTask1.start();
ThreadTaskDemo1 threadTask2 = new ThreadTaskDemo1();
threadTask2.setName("task-2");
threadTask2.start();
}
class ThreadTaskDemo1 extends Thread{
@Override
public void run() {
System.out.println("thread name:"+Thread.currentThread().getName());
}
}
}
运行输出
实现Runnable接口创建线程
Thread task1 = new Thread(new RunnableTaskDemo());
task1.setName("task-r1");
task1.start();
Thread task2 = new Thread(new RunnableTaskDemo());
task2.setName("task-r2");
task2.start();
实现Runnable接口,重写run方法
class RunnableTaskDemo implements Runnable{
@Override
public void run() {
System.out.println("thread name:"+Thread.currentThread().getName());
}
}
运行结果
这两种创建方式最主要的区别如果是实现Runnable接口的方式创建,可以给多个Thread用,这样的话可以很容易实现共享数据。但要注意避免线程安全问题。而使用继承Thread的方式创建线程则无法共享数据,一般推荐使用实现Runnable接口来创建线程,
实现Runnable创建线程的好处有:
- 在java中,因为类是单继承的,而类是可以继承多个接口的,避免了继承的局限 。
2. 容易实现资源的共享,适合多个线程去处理同一个资源。
3. 增加程序的健壮性
AsyncTask
首先AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以在线程池中执行后台任务,然后把执行的进度和结果传递给主线程并在主线程中更新UI。
AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。
其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。
public class MyAsyncTask extends AsyncTask<Integer, Integer, String> {
/* 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。
此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。
在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。*/
@Override
protected String doInBackground(Integer... params) {
return "ok";
}
//最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框/进度条显示
@Override
protected void onPreExecute() {
}
/*在doBackground方法中,每次调用publishProgress方法都会触发该方法
可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度
*/
@Override
protected void onProgressUpdate(Integer... values) {
}
/* 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。
此方法在主线程执行,任务执行的结果作为此方法的参数返回*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
// 用户调用取消时,要做的操作
@Override
protected void onCancelled() {
super.onCancelled();
}
}
使用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyAsyncTask task = new MyAsyncTask();
task.execute();
// task.execute(150);//也可以根据业务需求传参
}
AsyncTask的缺点:默认使用串行的线程池执行任务,也就是说,如果往这个池里创建10个AsyncTask任务,如有一个一直没结束,比如说阻塞,休眠,那么其他的就无法执行了。
在Android 1.6之前的版本,AsyncTask是串行的,在1.6到2.3的版本,改成了并行的。在2.3之后的版本又修改了,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor exec,Params… params)。
如
MyAsyncTask task = new MyAsyncTask();
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
AsyncTask第二种创建方式,直接执行Runnable接口实现类(串行执行)
AsyncTask.execute(()->{
System.out.println("AsyncTask thread name "+ Thread.currentThread().getName());
});
运行输出
//并行的执行方式
AsyncTask.THREAD_POOL_EXECUTOR.execute(()->{
System.out.println("AsyncTask thread name "+ Thread.currentThread().getName());
});
HandlerThread
HandlerThread适用于轮询场景,通过发送消息的形式执行任务,这也是一个串行的执行方式。这个用得比较少,一般是主线程的Handler用得比较多。在子线程给主线程发送消息。比如在子线程请求数据,然后向主线程发送结果。这里就列出代码,具体可百度。
其他
除了上面列出的方式,还有IntentService、ThreadPoolExecutor
IntentService是个服务,它可以在后台运行。一般用于我们需要跨界面获取到后台任务执行进度,比如说我们上传、下载文件,它执行完任务则会结束服务。
ThreadPoolExecutor 线程池重复使用线程,减少创建、销毁线程的开销,一般用于频繁的,消耗资源较少的操作。