Android开发 - Thread 线程UI主线程与后台运行多线程解析
什么是线程
- 线程就像是一条小路,允许程序在运行时同时做多件事。可以把它想象成一条跑道上跑步的跑者,而整个程序就是操场
线程的基本概念
-
线程是程序执行的基本单元。每个程序至少有一个线程(主线程),它负责执行程序中的代码
-
多线程:多个线程同时在运行,类似于操场上有多个跑步的跑者。这样可以让程序同时做更多的事情,例如同时下载文件和处理用户输入
为什么要用线程
- 提高效率:线程允许程序同时进行多项任务,例如:
- 下载文件的同时显示进度条
- 处理数据的同时响应用户点击
- 改善用户体验:如果一个应用程序只使用主线程(UI线程)来做所有的工作,比如下载数据或读取文件,用户界面可能会变得迟缓或无响应。使用线程可以避免这种情况,保持应用流畅
线程的工作原理
-
主线程(UI线程):这是程序启动时默认的线程,它处理用户界面和用户交互。主线程不能做耗时操作,比如网络请求,否则界面会变得卡顿
-
后台线程:用于执行耗时的操作,比如下载文件、处理大数据等。后台线程不会阻塞主线程,可以让主线程继续响应用户操作
线程的主要方法
-
thread.start()
:启动一个新线程。当调用thread.start()
方法时,线程会从run()
方法开始执行Thread thread = new Thread(new Runnable() { @Override public void run() { // 这是线程要做的工作 } }); thread.start(); // 启动线程
-
run()
:定义线程要执行的代码。当线程启动时,run()
方法里的代码会被执行new Thread(new Runnable() { @Override public void run() { System.out.println("线程在运行"); } }).start();
-
thread.sleep(long millis)
:当前线程暂停执行指定的时间(毫秒)。thread.sleep()
方法使线程暂停执行try { Thread.sleep(2000); // 休眠2秒 } catch (InterruptedException e) { e.printStackTrace(); }
- 参数解析:
- millis:当前线程暂停执行指定的时间(毫秒)
- 参数解析:
-
thread.join()
:等待当前线程完成。调用thread.join()
可以等到另一个线程结束Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("线程正在执行任务"); } }); thread.start(); try { thread.join(); // 等待线程完成 } catch (InterruptedException e) { e.printStackTrace(); }
-
thread.interrupt()
:中断线程的休眠或等待状态。它会中断线程的等待或休眠状态,并引发 InterruptedExceptionThread thread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); // 休眠5秒 } catch (InterruptedException e) { System.out.println("线程被中断"); } } }); thread.start(); thread.interrupt(); // 中断线程
-
thread.isAlive()
:检查线程是否还在运行Thread thread = new Thread(new Runnable() { @Override public void run() { // 执行任务 } }); thread.start(); System.out.println("线程是否还活着: " + thread.isAlive());
-
thread.setPriority(int priority)
:分配不同的任务优先级。优先级高的线程会优先获得CPU时间Thread thread = new Thread(new Runnable() { @Override public void run() { // 执行任务 } }); thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级 thread.start();
- 参数解析:
- priority:设置线程的优先级。通常取值为:
Thread.MIN_PRIORITY
、Thread.NORM_PRIORITY
、Thread.MAX_PRIORITY
- priority:设置线程的优先级。通常取值为:
- 参数解析:
主要方法总结
- 线程(Thread)是使程序可以同时执行多个任务的工具。主要方法包括:
start()
:启动线程,让它开始工作run()
:定义线程要执行的代码sleep(long millis)
:让线程暂停执行指定的时间join()
:等待线程完成任务interrupt()
:中断线程的休眠或等待状态isAlive()
:检查线程是否还在运行setPriority(int priority)
:设置线程的优先级
创建和使用线程
简单的线程
-
在后台做一个简单的任务,比如打印一条消息。可以创建一个线程来完成这个任务,而不会影响到主线程
// 创建一个新的线程 new Thread(new Runnable() { // 定义了线程中要执行的任务 @Override public void run() { // 这是在后台线程中运行的代码 System.out.println("后台任务执行中..."); } // 启动线程,线程开始执行run()方法中的代码 }).start();
线程池
-
如果有很多任务需要处理,创建和管理大量线程会很麻烦。线程池是一个很好的解决方案,它可以重用线程,管理线程的创建和销毁
// 创建一个线程池,最多同时运行4个线程 ExecutorService executor = Executors.newFixedThreadPool(4); // 将任务提交给线程池执行 executor.submit(new Runnable() { @Override public void run() { // 执行后台任务 System.out.println("线程池中的任务执行中..."); } }); //关闭线程池,不再接受新任务 executor.shutdown(); // 关闭线程池
线程与用户界面更新
-
只有主线程可以更新用户界面。如果后台线程需要更新UI,可以使用以下方法:
-
runOnUiThread()
:可以在主线程中执行代码runOnUiThread(new Runnable() { @Override public void run() { // 更新用户界面 myTextView.setText("更新了UI!"); } });
-
Handler
:用于在主线程和其他线程之间传递消息和任务Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // 更新UI myTextView.setText("更新了UI!"); } });
-
常见问题
-
死锁:当两个或多个线程互相等待对方释放资源,导致所有线程都无法继续运行。避免死锁的方法包括避免嵌套锁定和确保锁的获取顺序一致
-
资源竞争:当多个线程同时访问共享资源而导致的冲突。使用同步机制(如 synchronized 关键字或 Lock 类)可以避免资源竞争
总结
-
线程允许程序同时进行多个任务,提高效率和用户体验
-
使用线程可以保持应用的流畅性,避免界面冻结
-
线程池是管理大量线程的有效工具
-
线程与UI更新需要特别注意,通常使用
runOnUiThread()
或 Handler 来确保UI更新在主线程中进行