首页 > 编程语言 >Android 多线程编程 - 线程的基本使用

Android 多线程编程 - 线程的基本使用

时间:2023-07-25 20:06:22浏览次数:44  
标签:Runnable run Thread void 线程 Android 多线程 public

1.线程的状态

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

2. 创建线程

线程的创建一般有以下3种方法,其中前两种为常用的方法。

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

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

public class TestThread extends Thread{
        @Override
        public void run() {
            super.run();
            System.out.println("Hello World!");
        }
        public static void main(String[] args) {
            Thread thread = new TestThread();
            thread.start();
        }
    }

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

实现步骤如下:

  1. 自定义类并实现Runnable接口,实现run方法。
  2. 创建Thread子类的实例,用实现Runnable接口的对象作为参数实例化该Thread对象
  3. 调用Thread的start方法来启动该线程。
public class TestRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("Hello World!");
        }
        public static void main(String[] args) {
            TestRunnable testRunnable = new TestRunnable();
            Thread thread = new Thread(testRunnable);
            thread.start();
        }
    }

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

Callable接口实际是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable接口更强大的功能,主要表现为以下3点:

  1. Callable可以在任务接受后提供一个返回值,Runnable无法提供这个功能。
  2. Callable中的call方法可以抛出异常,而Runnable的run方法不能抛出异常。
  3. 运行Callable可以拿到一个Future对象;Future对象表示异步计算的结果,它提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下就可以使用Future来监视目标线程调用call方法的情况。但调用Future的get方法以获取结果时,当前线程就会被阻塞,直到call方法返回结果。
public class TestCallable {

        public static class MyTestCallable implements Callable {
            @Override
            public String call() throws Exception {
                return "Hello World";
            }
        }

        public static void main(String[] args) {
            MyTestCallable myTestCallable = new MyTestCallable();
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            Future future = executorService.submit(myTestCallable);
            try {
                System.out.println(future.get());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

3. 终止线程

3.1. 理解中断

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

while (!Thread.currentThread().isInterrupted()){
    //do something
}

还可以调用Thread.interrupted()来对中断标识位进行复位。但是如果一个线程被阻塞,就无法检测中断状态。如果一个线程处于阻塞状态,那么线程在检测标识位时若发现中断标识位为true,则会在阻塞方法调用处抛出InterruptedException异常,并且在抛出异常前将线程的中断标识位复位,即重新设置为false,被中断的线程可以决定如何去响应中断。如果是比较重要的线程,则不会理会中断;而大部分情况则是线程会将中断作为一个终止的请求。另外,不要在底层代码里捕获InterruptedException异常后不做处理。如果不知道抛出InterrptedException异常后如何处理,这里介绍两种合理的处理方式:

  1. 在catch子句中,调用Thread.currentThread.interrupt()来设置中断状态(因为抛出异常后中断标识位会复位),让外界通过判断Thread.currentThread().isInterrupted()来决定是终止线程还是继续下去。
void myTask(){
    ...
    try {
        sleep(50);
    }catch (InterruptedException e){
        Thread.currentThread().interrupt();
    }
}
  1. 更好的做法就是,不使用try来捕获这样的异常,让方法直接抛出,这样调用者可以捕获这个异常,如下所示:
void myTask() throws InterruptedException{
    sleep(50);
}

3.2. 安全的终止线程

  1. 使用中断来终止线程
public class StopThread {
    public static void main(String[] args) {
        MoonRunner runnable = new MoonRunner();
        Thread thread = new Thread(runnable);
        thread.start();
        try {
            TimeUnit.MILLISECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
    public static class MoonRunner implements Runnable{
        private long i;
        
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                i++;
                System.out.println("i=" + i);
            } 
            System.out.println("stop");
        }
    }
}
  1. 采用boolean变量来控制是否终止线程
public class StopThread2 {
    public static void main(String[] args) throws InterruptedException {
        MoonRunner runnable = new MoonRunner();
        Thread thread = new Thread(runnable);
        thread.start();
        TimeUnit.MILLISECONDS.sleep(10);
        runnable.cancel();
    }
    public static class MoonRunner implements Runnable {
        private long i;
        private volatile boolean on = true;

        @Override
        public void run() {
            while (on) {
                i++;
                System.out.println("i=" + i);
            }
            System.out.println("stop");
        }
        public void cancel(){
            on = false;
        }
    }
    
}

标签:Runnable,run,Thread,void,线程,Android,多线程,public
From: https://blog.51cto.com/u_16175630/6848802

相关文章

  • Python time模块和datetime模块,以及多线程
    1.time模块1.1time.time()函数time.time()函数返回自1970年1月1日0点到现在的秒数。纪元时间戳可以用于剖析代码,也就是测量一段代码的运行时间。如果在代码块开始时调用time.time(),并在结束时再次打开,就可以用第二个时间戳减去第一个,得到这两次调用之间经过的时间。......
  • 线程池问题记录以及处理
    现象每天到业务高峰期就会出现提交线程被拒绝。疑问点什么原因会导致activethreads远远小于poolsize的情况下,提交任务失败关键信息线程池配置ExecutorServiceaService=newThreadPoolExecutor(130,300,60L......
  • 在互联网就业困难的行情下,Android开发如何提升自身竞争力,找到高薪工作?
    前言经历了3年之久的疫情困扰、终于解封了。本以为解封后市场行情会一片大好、想象着和以前来个跳槽涨薪、然后坐上技术VP、走上人身巅峰…结果现实给了狠狠一记耳光、还按在地上使劲摩擦。结果脸肿了、幸好腿还没断。自我介绍一下本人男28岁,一名andriod开发程序员,工作有将近五年......
  • 线程池
    线程池的组成1、线程管理器(ThreadPool)2、工作线程(PoolWorker)3、任务接口(Task)4、任务队列(taskQueue)初始化参数corePoolSize:核心线程数maxmumPoolSize:最大线程数keepAliveTime和TimeUnit:空闲线程存活时间及单位workQueue:工作队列,必须是BlockingQueue常见线程池newCachedThreadPool(......
  • ubuntu android adb 环境变量配置
    UbuntuAndroidADB环境变量配置简介在开发Android应用程序时,ADB(AndroidDebugBridge)是一个非常重要的工具。ADB提供了与Android设备进行通信的能力,可以用于应用程序的调试、安装、卸载等操作。本文将介绍如何在Ubuntu系统下配置ADB环境变量,以便能够在任何目录下直接......
  • 用android studio 绘制行数不确定的表格
    用AndroidStudio绘制行数不确定的表格介绍在Android应用开发中,我们经常需要绘制表格来展示数据。有时候,表格的行数是不确定的,这就需要我们动态地生成表格,并根据数据的变化来更新表格的行数。本文将向你介绍如何使用AndroidStudio来实现这个功能。步骤步骤1:创建一个新的Andr......
  • 视频直播源码,Android自定义Spinner样式
    视频直播源码,Android自定义Spinner样式设置Spinner的背景图,如下代码:   <Spinner          android:id="@+id/sp_gender"          android:layout_width="match_parent"          android:layout_height="mat......
  • java多线程内存图
    多线程的例子例一:publicclassTest{publicstaticvoidmain(String[]args)throwsException{Threadx1=newThread(){@Overridepublicvoidrun(){for(inti=0;i<100;i++){Syst......
  • Android 双击点亮屏幕
    1.修改配置:frameworks\base\services\core\java\com\android\server\power\PowerManagerService.javamSupportsDoubleTapWakeConfig=resources.getBoolean(com.android.internal.R.bool.config_supportDoubleTapWake);if(mSupportsDoubleTapWakeConfig){......
  • Android应用数据安全存储加固
    目前移动领域已经出现了相当部分的安全问题,新的恶意软件层出不穷,另一方面,企业对敏感数据保密性意识日益提高,作为移动开发者,有责任对最终用户的隐私和安全承担更多责任。本文主要讨论移动安全存储策略,设计了安全加固方案,实现了移动应用逆向分析、安全代码自动注入等全流程的一键式加......