Android开发中的多线程


多线程案例——计时器

这个案例中,屏幕启动之后,进入如图所示的界面。

屏幕上有一个文本框用于显示逝去的时间,此外还有一个“停止计时”按钮。案例的用例图如图所示。

能够在屏幕上“实时地显示”时间的流逝,单线程程序是无法实现的,必须要多线程程序才可以实现,即便有些计算机语言可以通过封装好的类实现这一功能,但从本质上讲这些封装好的类就是封装了一个线程。

综上所述,完成本案例用到的知识及技术如下:

  1)进程和线程的概念;

  2)Java中的线程,在Java中创建线程的方式;

  3)Android中的线程,包括:Message、Handler、Looper和HandlerThread等概念。

线程究竟是什么?在Windows操作系统出现之前,个人计算机上的操作系统都是单任务系统,只有在大型计算机上才具有多任务和分时设计。Windows、Linux操作系统的出现,把原本只在大型计算机才具有的优点,带到了个人计算机系统中。

进程概念

  一般可以在同一时间内执行多个程序的操作系统都有进程的概念。一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。在进程的概念中,每一个进程的内部数据和状态都是完全独立的。在Windows操作系统下我们可以通过〈Ctrl+Alt+Del〉组合键查看进程,在UNIX和Linux操作系统下是通过PS命令查看进程的。打开Windows当前运行的进程,如图所示。

在Windows操作系统中一个进程就是一个exe或dll程序,它们相互独立,互相也可以通信,在Android操作系统中进程间的通信应用也是很多的。

线程概念

  多线程指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务。多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行。

  线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制。但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,所以系统在各个线程之间切换时,资源占用要比进程小得多,正因如此,线程也被称为轻量级进程。一个进程中可以包含多个线程。图所示是计时器程序进程和线程之间的关系,主线程负责管理子线程,即子线程的启动、挂起、停止等操作。

 

Android 4.4.4 发布下载

最简单的Ubuntu Touch & Android 双系统安装方式

在Nexus上实现Ubuntu和Android 4.4.2 双启动

Ubuntu 14.04 配置 Android SDK 开发环境

64位Ubuntu 11.10下Android开发环境的搭建(JDK+Eclipse+ADT+Android SDK详细)

Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法

Ubuntu 12.10 x64 安装 Android SDK

Java中的线程

  Java的线程类是java.lang.Thread类。当生成一个Thread类的对象之后,一个新的线程就产生了。Java中每个线程都是通过某个特定Thread对象的方法run()来完成其操作的,方法run( )称为线程体。

  下面是构建线程类几种常用的方法:

  public Thread()

  public Thread(Runnable target)

  public Thread(Runnable target, String name)

  public Thread(String name)

  参数target是一个实现Runnable接口的实例,它的作用是实现线程体的run()方法。目标target可为null,表示由本身实例来执行线程。name参数指定线程名字,但没有指定的构造方法,线程的名字是JVM分配的,例如JVM指定为thread-1、thread-2等名字。

1、Java中的实现线程体方式1

  在Java中有两种方法实现线程体:一是继承线程类Thread,二是实现接口Runnable。下面我们先看看继承线程类Thread方式。

如果采用第1种方式,它继承线程类Thread并重写其中的方法 run(),在初始化这个类实例的时候,目标target可为null,表示由本实例来执行线程体。由于Java只支持单重继承,用这种方法定义的类不能再继承其他父类,例如代码清单如图:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class textThread extends Thread {
    boolean flag = true;
    int timer = 0;

    @Override
    public void run() {
        super.run();
        try {
            while (flag) {
                this.currentThread().sleep(1000);
                timer++;
                System.out.print(timer);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        textThread thread = new textThread();
        thread.start();
        System.out.print("启动计时器...");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   
        try {
            String line = reader.readLine();
            if(line.equalsIgnoreCase("1")){
                //thread.stop();
                thread.flag = false;
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在main主方法中通过new textThread()创建子线程,并通过thread.start()方法启动子线程,main主方法所在线程为主线程,主线程负责管理其他的子线程。本例进程、主线程和子线程之间的关系如图所示。

  子线程启动之后就开始调用run()方法,run()是一个线程体,我们在子线程中处理事情就是在这里编写代码实现的。本案例中子线程要做的事情就是:休眠1s,计时器加1,再反复执行。Thread.currentThread().sleep(1000)就是休眠1s。

  为了能够停止线程,我们在主线程中增加了一个标识,通过在控制台输入一个字符

  “1”来改变该标识t1.isRunning = false,从而结束这个线程。

注意:

  事实上线程中有一个stop()方法也可以停止线程,但是由于这种方法会产生线程死锁问题,所以在新版JDK中已经废止了,它的替代解决方法就是增加标识,就是我们在本例中采用的方案。

  很多人觉得线程难理解,主要有两个问题:

  线程休眠,既然线程已经休眠了,程序的运行速度还能提高吗?

  线程体一般都进行死循环,既然线程死循环,程序就应该死掉了,就会没有反应。

  1.关于线程休眠问题

  对线程休眠问题头痛的读者,其实还是在用单线程的思维模式考虑问题,多数情况下我们的PC都是单CPU的,某个时间点只能有一个线程运行。所谓多线程就是多个线程交替执行就好像同时运行似的。因此,休眠当前线程可以交出CPU控制权,让其他的线程有机会运行,多个线程之间只有交替运行效率才是最高的,这就像我们开车过十字路口,只有我等等,让你先过,你再等等让他先过,才能保证最高效率,否则就会造成交通系统崩溃,对线程情况也是一样的。因此,多线程中线程的休眠是程序运行的最有效方式。

  2.关于线程体死循环问题

  在单线程中如果是死循环,程序应就会死掉,没有反应,但是多线程中线程体(run方法)中的死循环,可以保证线程一直运行,如果不循环线程,则运行一次就停止了。在上面的例子中线程体运行死循环,可以保证线程一直运行,每次运行都休眠1s,然后唤醒,再然后把时间信息输出到控制台。所以,线程体死循环是保证子线程一直运行的前提。由于是子线程它不会堵塞主线程,就不会感觉到程序死掉了。但是需要注意的是有时我们确实执行一次线程体,就不需要循环了。

 程序运行后开始启动线程,线程启动后就计算逝去的时间,每过1s将结果输出到控制台。当输入1字符后线程停止,程序终止。如图所示。

更多详情见请继续阅读下一页的精彩内容:

  • 1
  • 2
  • 3
  • 4
  • 下一页

相关内容