首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Android多线程编程——线程基础

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

作者头像
Petterp
发布2022-02-09 11:27:43
发布2022-02-09 11:27:43
4890
举报
文章被收录于专栏:JetPackJetPack

目录

1. 进程与线程

什么是进程?

什么是线程?

为什么要使用多线程?

2.线程的状态

3.创建线程

4.中断

5.安全的终止线程

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

1. 进程与线程

什么是进程?

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

什么是线程?

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

为什么要使用多线程?

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

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

2.线程的状态

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

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

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

3.创建线程

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

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

代码语言:javascript
复制
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方法

代码语言:javascript
复制
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 方法返回结果。
代码语言:javascript
复制
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()

代码语言:javascript
复制
while(!Thread.currentThread().isIntterrupted()){
    
}

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

代码语言:javascript
复制
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()来决定是否终止线程还是继续下去。
代码语言:javascript
复制
class TestCallable extends Thread{
    @Override
    public  void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    interrupted();
                }
            }
    }

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

代码语言:javascript
复制
class TestCallable extends Thread {
    @Override
    public void run() {
 
    }
    void myTask() throws InterruptedException {
        sleep(5000);
    }
}

5.安全的终止线程

代码语言:javascript
复制
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();
    }
}

还可以改写成如下写法

代码语言:javascript
复制
class TestCallable extends Thread {
    int i=0;
    private volatile  boolean on=true;
    @Override
    public void run() {
        while (on){
            System.out.println(i++);
        }
        System.out.println("stop");
    }
    public void cancel(){
        on=false;
    }
}
 
 
 
public class MyClass {
    public static void main(String[] args) throws InterruptedException {
        final TestCallable tes=new TestCallable();
        tes.start();
        TimeUnit.MILLISECONDS.sleep(100);
        tes.cancel();
    }
}
  
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 进程与线程
    • 什么是进程?
    • 什么是线程?
    • 为什么要使用多线程?
  • 2.线程的状态
  • 3.创建线程
  • 4.中断
  • 5.安全的终止线程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档