Android多线程编程——线程基础

简介: Android沿用了Java的线程模型,一个Android应用在创建的时候会开启一个线程,我们叫它主线程或者UI线程。

Android沿用了Java的线程模型,一个Android应用在创建的时候会开启一个线程,我们叫它主线程或者UI线程。

如果我们想要访问网络或者数据库等耗时操作,都会开启子线程去处理,从 Android3.0 开始,系统要求网络访问必须在子线程中进行,否则会抛出异常;也就是为了避免主线程被耗时操作阻塞从而产生 ANR。

1. 进程与线程

什么是进程?

进程是操作系统结构的基础,是程序在一个数据集合上运行的过程,是系统进行资源分配和调度的基本单位。进程可以看做是程序的实体,同时,他也是线程的容器。

什么是线程?

线程是操作系统调度的最小单元,也叫轻量级进程。在一个进程中可以创建多个线程,这些线程都拥有各自的计数器,堆栈和局部变量等属性,并且能够访问共享的内存变量。

为什么要使用多线程

在操作系统级别上来看主要有以下几个方面:

  • 使用多线程可以减少程序的响应时间。
  • 与进程相比,线程的创建和切换开销更小,同时多线程在数据共享方面效率非常高。
  • 使用多线程能简化程序的结构,使程序便于理解和维护。

2.线程的状态

Java的线程运行的声明周期中可能会处于6中不同的状态。

  • New 新创建状态。线程被创建,还没有调用Start方法,在线程运行之前还有一些基础工作要做。
  • Runnable 可运行状态。一旦调用start方法,线程就处于 Runnable状态。一个可运行的线程可能正在运行也可能没有运行,这取决于操作系统给线程提供运行的时间。
  • Blocked 阻塞状态。表示线程被锁阻塞,它暂时不活动。
  • Waiting 等待状态,线程暂时不活动,并且不运行任何代码,这消耗最少的资源,直到线程调度器重新激活它。
  • Timed waiting 超时等待状态。和等待状态不同的是,它是可以在指定的时间自行返回的。
  • Terminated 终止状态。 表示当前线程已经执行完毕。导致线程终止有两种情况: 第一种就是run方法执行完毕正常退出;第二种就是因为没有一个捕获的异常而终止了 run方法,导致线程进入了终止状态。

image.png

线程创建后,调用Thread 的 Start方法,开始进入运行状态,当线程执行 wait 方法后,线程进入等待状态,进入等待状态的线程需要其他线程通知才能返回运行状态。超时等待相当于在等待状态加上了时间限制,如果超过时间限制,则线程返回运行状态。当线程调用到同步方法时,如果线程没有获得所则进入阻塞状态,当阻塞状态的线程获取到锁是则重新回到运行状态。当线程执行完毕或者遇到以外异常终止时,都会进入终止状态。

3.创建线程

  1.继承Thread类,重写run方法

Thrad本质上也是实现了 Runnable接口的一个实例。需要注意的是调用 start方法后并不是立即执行多线程的代码,而是使该线程变为可运行状态,什么时候运行多线程代码是否操作系统决定的。

public class MyClass extends Thread{
    @Override
    public void run() {
        System.out.println("Petterp");
    }
    public static void main(String[] args) {
        MyClass myClass=new MyClass();
        myClass.start();
    }
}

  2.实现Runnable接口,并实现该接口的run方法

public class MyClass extends Thread{
    @Override
    public void run() {
        System.out.println("Petterp");
    }
    public static void main(String[] args) {
        MyClass myClass=new MyClass();
        myClass.start();
    }
}

  3.实现Callable接口,重写call方法

Callable接口是属于Expecutor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更强大的功能

  • Callable 可以在任务接受后提供一个返回值,Runnable无法提供这个功能。
  • Callable 中的call方法可以抛出异常,而Runnable的fun方法不能抛出异常。
  • 运行Callable 可以拿到一个 Future的对象,Future对象表示异步计算得到的结果,他提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下就可以使用 Future 来监视目标线程调用 call 方法的情况。但调用 Future的 get() 方法以获取结果是,当前线程就会阻塞,直到 call 方法返回结果。
class TestCallable implements Callable{
        public Object call() throws Exception {
            Thread.sleep(1000);
            return "Petterp";
        }
    }
public class MyClass {
    public static void main(String[] args) {
        TestCallable testCallable=new TestCallable();
        ExecutorService service= Executors.newCachedThreadPool();
        Future future=service.submit(testCallable);
        try {
            //等待线程结束,并返回结果
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4.中断

当线程的run方法执行完毕,或者在方法中出现没有捕获的异常时,线程将终止。在Java早期版本中有一个Stop方法,其他线程可以调用它终止线程,但是这个方法现在已经被弃用了。interrupt 方法可以用来请求中断线程。当一个线程调用 interrupt 方法时,线程的中断标识位将被置位(中断标识位为 true),线程会不时的检测这个中断标识位,以判断线程是否应该被中断。要想知道线程是否被置位,可以调用Thread.currentThread().inInterrupted()

while(!Thread.currentThread().isIntterrupted()){
}

还可以调用Thread.interrupted() 来对中断标识位进行复位。但是如果一个线程被阻塞,就无法检测中断状态。如果一个线程处于阻塞状态,线程在检查中断标识符是如果发现中断标识位为 true,则会在阻塞方法调用处抛出 InterruptedException 异常,并且在抛出异常前将线程的中断标识位复位,即重新设置为false,需要注意的是被中断的线程不一定会终止,中断线程是为了引起线程的注意,被中断的线程可以决定如何去响应中断,如果是比较重要的线程则不会理会中断,而大部分情况则是线程会将中断作为一个终止的请求。另外,不要在底层代码里捕获 InterruptedExcepetion 异常后不做处理:如下所示

class TestCallable extends Thread{
    @Override
    public  void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }

可以使用以下两种方式处理异常:

  1. 在catch 语句中,调用Thread.currentThread.interrupt() 来设置中断状态(因为抛出异常后中断标识符为复位),让外界通过判断 Thread.currentThread().isInterrupted()来决定是否终止线程还是继续下去。
class TestCallable extends Thread{
    @Override
    public  void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    interrupted();
                }
            }
    }

2. 更好的做法就是,不适用try来捕获这样的异常,让方法直接抛出,这样调用者可以捕获这个异常,如下

class TestCallable extends Thread {
    @Override
    public void run() {
    }
    void myTask() throws InterruptedException {
        sleep(5000);
    }
}

5.安全的终止线程

class TestCallable extends Thread {
    int i=0;
    @Override
    public void run() {
        System.out.println(i++);
    }
}
public class MyClass {
    public static void main(String[] args) throws InterruptedException {
        final TestCallable tes=new TestCallable();
        tes.start();
        TimeUnit.MILLISECONDS.sleep(10);
        tes.interrupt();
    }
}

还可以改写成如下写法

目录
相关文章
|
1月前
|
Java 调度 Android开发
构建高效Android应用:探究Kotlin多线程编程
【2月更文挑战第17天】 在现代移动开发领域,性能优化一直是开发者关注的焦点。特别是在Android平台上,合理利用多线程技术可以显著提升应用程序的响应性和用户体验。本文将深入探讨使用Kotlin进行Android多线程编程的策略与实践,旨在为开发者提供系统化的解决方案和性能提升技巧。我们将从基础概念入手,逐步介绍高级特性,并通过实际案例分析如何有效利用Kotlin协程、线程池以及异步任务处理机制来构建一个更加高效的Android应用。
41 4
|
1月前
|
API 数据库 Android开发
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第14天】随着移动设备性能的日益强大,用户对应用程序的响应速度和流畅性要求越来越高。在Android开发中,合理利用多线程技术是提升应用性能的关键手段之一。Kotlin作为一种现代的编程语言,其协程特性为开发者提供了更为简洁高效的多线程处理方式。本文将深入探讨使用Kotlin进行Android多线程编程的最佳实践,包括协程的基本概念、优势以及在实际项目中的应用场景和性能优化技巧,旨在帮助开发者构建更加高效稳定的Android应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
47 0
|
3月前
|
设计模式 消息中间件 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(二)
34 1
|
12天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
23天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
1月前
|
Java Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第17天】 随着移动设备性能的不断提升,用户对应用的响应速度和稳定性要求越来越高。在Android开发中,Kotlin语言以其简洁、安全的特点受到开发者青睐。然而,面对复杂的多线程任务,如何有效利用Kotlin进行优化,以提升应用性能,是本文探讨的重点。通过分析Kotlin并发工具的使用场景与限制,结合实例演示其在Android开发中的实践,旨在为开发者提供实用的多线程处理指南。
|
3月前
|
设计模式 存储 Java
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(四)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(四)
93 1
|
3月前
|
设计模式 存储 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(三)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(三)
38 2
|
3月前
|
设计模式 Java 关系型数据库
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(一)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(一)
29 0

热门文章

最新文章