1、第八章第八章 JAVA JAVA多线程编程多线程编程本章学习要点本章学习要点 了解进程和线程的概念;掌握Thread类的使用;掌握Runnable接口的使用;熟悉线程的生命周期;了解线程同步;熟悉各种操作线程的方法;掌握停止线程的方法;掌握暂停线程的方法;熟悉线程的优先级和实现。8.1 JAVA 8.1 JAVA线程的概念线程的概念 世间万物都可以同时完成很多工作。例如,人体可以同时进行呼吸、血液循环、思考问题等活动。用户既可以使用计算机听歌,也可以编写文档和发送邮件,而这些活动的完成可以同时进行。这种同时执行多个操作的“思想”在Java中被称为并发,而将并发完成的每一件事称为线程。在Java
2、中,并发机制非常重要,但并不是所有程序语言都支持线程。在以往的程序中,多以一个任务完成以后再进行下一个任务的模式进行,这样下一个任务的开始必须等待前一个任务的结束。Java语言提供了并发机制,允许开发人员在程序中执行多个线程,每个线程完成一个功能,并与其他线程并发执行。这种机制被称为多线程。8.1 JAVA 8.1 JAVA线程的概念线程的概念 Java中的多线程在每个操作系统中的运行方式也存在差异,在此以Windows操作系统为例介绍其运行模式。Windows系统是多任务操作系统,它以进程为单位。一个进程是一个包含有自身地址的程序,每个独立执行的程序都称为进程,也就是正在执行的程序。系统可以
3、分配给每个进程一段有限的执行CPU的时间(也称为CPU时间片),CPU在这段时间中执行某个进程,然后下一个时间段又跳到另一个进程中去执行。由于CPU切换的速度非常快,给使用者的感受就是这些任务似乎在同时运行,所以使用多线程技术后,可以在同一时间内运行更多不同种类的任务。8.1 JAVA 8.1 JAVA线程的概念线程的概念 那么什么是线程呢?线程可以理解成是在进程中独立运行的子任务。比如,QQ.exe运行时就有很多的子任务在同时运行。像好友视频、下载文件、传输数据、发送表情等,这些不同的任务或者说功能都可以同时运行,其中每一项任务完全可以理解成是“线程”在工作,传文件、听音乐、发送图片表情等功
4、能都有对应的线程在后台默默地运行。8.2 JAVA 8.2 JAVA多线程的实现方式多线程的实现方式 8.2.1 8.2.1 继承继承ThreadThread类类 8.2.2 8.2.2 实现实现RunnableRunnable接口接口 8.2.1 8.2.1 继承继承THREADTHREAD类类 在学习如何实现多线程前,先来看看Thread类的结构,如下:public class Thread implements Runnable 从上面的源代码可以发现,Thread类实现了Runnable接口,它们之间具有多态关系。其实,使用继承Thread类的方式实现多线程,最大的局限就是不支持多继承
5、,因为Java语言的特点就是单根继承,所以为了支持多继承,完全可以实现Runnable接口的方式,一边实现一边继承。8.2.1 8.2.1 继承继承THREADTHREAD类类 构造方法方法方法说明说明Thread()Thread()分配一个新的 Thread对象。Thread(String name)Thread(String name)分配一个新的 Thread对象。name为其名称 Thread(Runnable target)Thread(Runnable target)分配一个新的 Thread对象。Thread(Runnable target,String name)Thread(
6、Runnable target,String name)分配一个新的 Thread对象。使其具有 target作为其运行对象,具有指定的 name作为其名称。8.2.1 8.2.1 继承继承THREADTHREAD类类 线程实现的业务代码需要放到run()方法中。当一个类继承Thread类后,就可以在该类中覆盖run()方法,将实现线程功能代码写入run()方法中,然后同时调用Thread类的start()方法执行线程,也就是调用run()方法。Thread对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run()方法中。当执行一个线程程序时,就会自动产生一个线程
7、,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序。主方法线程启动由Java虚拟机负责,开发人员负责启动自己的线程。8.2.2 8.2.2 实现实现RUNNABLERUNNABLE接口接口 如果要创建的线程类已经有一个父类,这时就不能再继承Thread类,因为Java不支持多继承,所以需要实现Runnable接口来应对这样的情况。实现Runnable接口的语法格式如下:public class thread extends Object implements Runnable 提示:从JDK的API中可以发现,实质上Thread类实现了Runnable接口,其中的run
8、()方法正是对Runnable接口中run()方法的具体实现。8.2.2 8.2.2 实现实现RUNNABLERUNNABLE接口接口 Runnable接口启动线程的基本步骤如下。创建一个Runnable对象。使用参数带Runnable对象的构造方法创建Thread实例。调用start()方法启动线程。通过实现Runnable接口创建线程时开发人员首先需要编写一个实现Runnable接口的类,然后实例化该类的对象,这样就创建了Runnable对象。接下来使用相应的构造方法创建Thread实例。最后使用该实例调用Thread类的start()方法启动线程8.3 JAVA8.3 JAVA多线程之间
9、访问实例变量多线程之间访问实例变量 自定义线程类中的实例变量针对其他线程可以有共享与不共享之分,这在多个线程之间进行交互时是很重要的一个技术点。在不共享数据时每个线程都拥有自己作用域的变量,且多个线程之间相同变量名的值也不相同。共享数据的情况就是多个线程可以访问同一个变量,比如在实现投票功能的软件时,多个线程可以同时处理同一个人的票数。8.4 JAVA JAVA多线程的同步机制多线程的同步机制 如果程序是单线程的,就不必担心此线程在执行时被其他线程“打扰”,就像在现实世界中,在一段时间内如果只能完成一件事情,不用担心做这件事情被其他事情打扰。但是,如果程序中同时使用多线程,好比现实中的“两个人
10、同时通过一扇门”,这时就需要控制,否则容易引起阻塞。为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制,指的是两个线程同时作用在一个对象上,应该保持对象数据的统一性和整体性。Java提供synchronized关键字,为防止资源冲突提供了内置支持。共享资源一般是文件、输入/输出端口或打印机。8.4 JAVA JAVA多线程的同步机制多线程的同步机制 在一个类中,用synchronized关键字声明的方法为同步方法。格式如下:class类名 public synchronized 类型名称 方法名称()/代码 Java有一个专门负责管理线程对象中同步方法访问的工具同步模型监视器,它的原理是
11、为每个具有同步代码的对象准备唯一的一把“锁”。当多个线程访问对象时,只有取得锁的线程才能进入同步方法,其他访问共享对象的线程停留在对象中等待。8.4 JAVA JAVA多线程的同步机制多线程的同步机制 synchronized不仅可以用到同步方法,也可以用到同步块。对于同步块,synchronized获取的是参数中的对象锁。格式如下:synchronized(obj)/代码 当线程执行到这里的同步块时,它必须获取obj这个对象的锁才能执行同步块,否则线程只能等待获得锁。必须注意的是,Obj对象的作用范围不同,控制情况也不尽相同。8.5 本章小结本章小结 如果一次只完成一件事情,很容易实现。但是现实生活中很多事情都是同时进行的,所以在Java中为了模拟这种状态,引入了线程机制。简单地说,当程序同时完成多件事情时,就是所谓的多线程程序。多线程的应用相当广泛,使用多线程可以创建窗口程序、网络程序等。本章由浅入深地介绍多线程,除了介绍其概念之外,还结合实例让读者了解如何使程序具有多线程功能。