《Java程序设计基础》第12章:多线程处理

  • 格式:ppt
  • 大小:243.50 KB
  • 文档页数:46

下载文档原格式

  / 46
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

利用多线程机制,Java使整个执行环境是异步的, 利用多线程机制,Java使整个执行环境是异步的,在 使整个执行环境是异步的 Java程序里没有主消息循环 程序里没有主消息循环。 Java程序里没有主消息循环。 Java语言里,线程表现为线程类(Thread), Java语言里,线程表现为线程类(Thread),线程类封 语言里 (Thread) 装了所有需要的线程操作控制。 装了所有需要的线程操作控制。 线程对象和运行线程: 线程对象和运行线程:线程对象可以看做是运行线程 的控制面板。线程类是控制线程行为的惟一手段。 的控制面板。线程类是控制线程行为的惟一手段。
3.阻塞线程
线程进入阻塞(NonRunnable)状态可能由以下3种情况造成: 线程进入阻塞(NonRunnable)状态可能由以下3种情况造成: (NonRunnable)状态可能由以下 调用sleep()方法。 sleep()方法 调用sleep()方法。 调用了wait()方法以等待某种事件的发生。 wait()方法以等待某种事件的发生 调用了wait()方法以等待某种事件的发生。 线程等待IO请求的完成。 IO请求的完成 线程等待IO请求的完成。 对于上述3种造成阻塞的情况, 对于上述3种造成阻塞的情况,分别有对应的不同条件可以 使线程恢复到运行状态。 使线程恢复到运行状态。 对于被调用了sleep()方法的,必须等待sleep时间过去。 sleep()方法的 sleep时间过去 对于被调用了sleep()方法的,必须等待sleep时间过去。 对于调用了wait()方法的线程,必须等到其他线程通过notify wait()方法的线程 notify或 对于调用了wait()方法的线程,必须等到其他线程通过notify或 notifyAll方法通知该线程它要等待的事件发生为止 方法通知该线程它要等待的事件发生为止, 者notifyAll方法通知该线程它要等待的事件发生为止,关于线 程间的通讯将在12.3节中介绍。 12.3节中介绍 程间的通讯将在12.3节中介绍。 对于被IO阻塞的线程,必须要等IO操作完成。 IO阻塞的线程 IO操作完成 对于被IO阻塞的线程,必须要等IO操作完成。
12.3 线程的管理 12.3.1 同步 12.3.2 优先级 12.3.3 有关线程的其他概念 12.4 用于制作动画的线程 12.4.1 动画程序框架 12.4.2 帧的画法 12.4.3 避免闪动 12.4.4 使用图片 12.5 练习题
12.1
线程的基本概念
12.1.1 程序与进程 程序是一个静态的概念,它是指用某种语言编写的, 程序是一个静态的概念,它是指用某种语言编写的,符合一定语 法规则并具有一定功能的一些指令的集合。程序往往有开始、 法规则并具有一定功能的一些指令的集合。程序往往有开始、处 理和结束3个部分组成。它的表现形式可能是一个文件, 理和结束3个部分组成。它的表现形式可能是一个文件,可能是 一组程序的集合(如一个大的应用程序) 一组程序的集合(如一个大的应用程序),总之它是一个完整的静 态概念。 态概念。 进程暂时简单理解为一段正在运行的程序,它是已经开始执行, 进程暂时简单理解为一段正在运行的程序,它是已经开始执行, 但尚未结束的一种程序的状态,因此,相对于程序来说, 但尚未结束的一种程序的状态,因此,相对于程序来说,进程可 以看作是一个动态的概念。 以看作是一个动态的概念。进程通常是一个可执行程序在内存中 的一个完整副本,每个进程都有自己的数据段、栈段和代码段, 的一个完整副本,每个进程都有自己的数据段、栈段和代码段, 因此它是一段完整的程序,在内存中占据较大的空间。 因此它是一段完整的程序,在内存中占据较大的空间。
12.2.1 线程的生命周期
在线程的一个完整生命周期中,共有4种可能 的状态以及5种常用的方法
例12.2 使用线程的时钟
一个称为Clock.class的Applet, 一个称为Clock.class的Applet,其功能是在屏幕上显示客户端 Clock.class 的当前系统时间。 的当前系统时间。这个例子利用了线程方法来实现了读取本地时 间的功能,其运行结果如图所示。 间的功能,其运行结果如图所示。
12.1.2
进程与线程
线程简单的说就是一种轻量级的进程, 线程简单的说就是一种轻量级的进程,它是一个程序 中实现单一功能的一个指令序列, 中实现单一功能的一个指令序列,它是一个程序的一 部分,不能单独运行,它必须在一个程序之内运行, 部分,不能单独运行,它必须在一个程序之内运行, 也就是说在一个进程的环境之中运行。 也就是说在一个进程的环境之中运行。 我们可以将一个进程按不同功能划分为多个线程, 我们可以将一个进程按不同功能划分为多个线程,将 线程在CPU上进行开销很小的调度, CPU上进行开销很小的调度 线程在CPU上进行开销很小的调度,因为线程只有自 己的栈段和程序计数器, 己的栈段和程序计数器,而没有独立的数据段和代码 因此,这种调度是非常轻量级的工作。 段。因此,这种调度是非常轻量级的工作。
4. 停止线程
线程的停止通常是等待run()方法执行结束之后自然地停止下来。 线程的停止通常是等待run()方法执行结束之后自然地停止下来。 run()方法执行结束之后自然地停止下来 线程被停止之后就转入到dead状态。 dead状态 线程被停止之后就转入到dead状态。 例如, Clock类中 run()方法的循环结束条件也就是线程结束 类中, 例如,在Clock类中,run()方法的循环结束条件也就是线程结束 的条件, myThread), 的条件,即while (clockThread == myThread),这个条件的含 义是当前线程不是clockThread的时候,这个线程就停止。 clockThread的时候 义是当前线程不是clockThread的时候,这个线程就停止。这就 意味着,当用户离开这个页面的时候,Applet会调用Clock的 会调用Clock 意味着,当用户离开这个页面的时候,Applet会调用Clock的 stop()方法 方法。 stop()方法。 源代码如下: 源代码如下: public void stop() { clockThread = null; }
12.1.3 Java的线程模型
Java的线程模型
图中一个程序(Prog. Cntr.)有 个线程组成, 图中一个程序(Prog. Cntr.)有N个线程组成,它们都有自己的 栈段(Local Stack),而所有的线程都可以共享Global Data, 栈段(Local Stack),而所有的线程都可以共享Global Data, 它们必须在这个程序的环境下执行。 它们必须在这个程序的环境下执行。
12.2 线程的基本结构与使用方法
Applet以及其他一些重要Java类一样 以及其他一些重要Java类一样, 和Applet以及其他一些重要Java类一样,一个 线程也有一些特定的状态以及和这些状态相对 应的方法,利用这些方法, 应的方法,利用这些方法,我们就可以对 Thread进行控制以及定义其功能 进行控制以及定义其功能。 Thread进行控制以及定义其功能。
1.创建新线程
Clock程序是在其start()方法中创建新线程的,其源代码如下: Clock程序是在其start()方法中创建新线程的,其源代码如下: 程序是在其start()方法中创建新线程的 public void start() { if (clockThread == null) { clockThread = new Thread(this, "Clock"); clockThread.start(); } } 在上述代码中的粗体字部分执行过后,对象clockThread就进入 在上述代码中的粗体字部分执行过后,对象clockThread就进入 clockThread 了新线程状态,一个新线程仅仅是一个空对象, 了新线程状态,一个新线程仅仅是一个空对象,它并没有被分配 给任何系统资源。 给任何系统资源。
进程调度: 进程调度:能够实现多任务的操作系统通过一定的算法将这样的 一个个进程排列成一个或多个队,一般情况下是采用FIFO FIFO, 一个个进程排列成一个或多个队,一般情况下是采用FIFO,即先 进先出的算法,有些进程由于其应用的特殊性可能会提高优先级, 进先出的算法,有些进程由于其应用的特殊性可能会提高优先级, 被排列在队伍的中间或者前面。同样,有些进程由于涉及过多IO 被排列在队伍的中间或者前面。同样,有些进程由于涉及过多IO 操作,可能会被执行到IO IO时 就调度到队伍的最后。 操作,可能会被执行到IO时,就调度到队伍的最后。这些进程按 照队伍排列好的顺序轮流被操作系统调入CPU执行。通常情况下, CPU执行 照队伍排列好的顺序轮流被操作系统调入CPU执行。通常情况下, 每个程序执行一个时间片就被调度下来,如果中间遇到有IO IO操作 每个程序执行一个时间片就被调度下来,如果中间遇到有IO操作 或者别的相对于CPU来说比较慢的操作, CPU来说比较慢的操作 或者别的相对于CPU来说比较慢的操作,或者有其他优先级高的 程序需要运行,该进程可能会被提前调度出CPU CPU。 程序需要运行,该进程可能会被提前调度出CPU。 时间片:操作系统自己管理的一个参数。 时间片:操作系统自己管理的一个参数。即指通常情况下每个进 程连续在CPU上执行的时间长度。 CPU上执行的时间长度 程连续在CPU上执行的时间长度。
第12章 多线程处理 章
学习重点:
程序、 程序、进程与线程的概念区别 Java中Thread的 Java中Thread的4种状态 Thread的典型应用 Thread的典型应用
第12章 多线程处理 章
12.1 线程的基本概念 12.1.1 程序与进程 12.1.2 进程与线程 12.1.3 Java的线程模型 12.2 线程的基本结构与使用方法 12.2.1 线程的生命周期 12.2.2 定制run()方法
例12.1 操纵当前线程
Βιβλιοθήκη Baidu
程序代码 打印当前线程实际上是t.toString()方法的省略写法,该方法能 打印当前线程实际上是t.toString()方法的省略写法, t.toString()方法的省略写法 够将这个线程的名字、优先级和其所属的线程组(ThreadGroup) 够将这个线程的名字、优先级和其所属的线程组(ThreadGroup) 打印出来。 打印出来。 Sleep()方法是使用类变量执行的 方法是使用类变量执行的, Sleep()方法是使用类变量执行的,原因在于这个方法是一个静 态方法,只能用类变量访问。 态方法,只能用类变量访问。 在线程进入sleep状态时,可能会被其他线程唤醒, sleep状态时 在线程进入sleep状态时,可能会被其他线程唤醒,这个时候就 会进入InterruptedException InterruptedException。 会进入InterruptedException。 运行结果如下图
事实上, 在某一时刻只能执行一个程序, 事实上,CPU在某一时刻只能执行一个程序,所有处于 在某一时刻只能执行一个程序 所有处于running状态的线程不可能同 状态的线程不可能同 时运行,因此,线程也必须向进程那样排好队,等待被调度到CPU上去。 上去。 时运行,因此,线程也必须向进程那样排好队,等待被调度到 上去
2.启动线程 public void start() { if (clockThread == null) { clockThread = new Thread(this, "Clock"); clockThread.start(); } }
线程的start()方法的作用是为这个线程对象创建它所需要的全 线程的start()方法的作用是为这个线程对象创建它所需要的全 start() 部系统资源,安排它的执行时间,并调用线程的run()方法。 run()方法 部系统资源,安排它的执行时间,并调用线程的run()方法。
Clock类中的run()方法。源代码如下: public void run() { Thread myThread = Thread.currentThread(); while (clockThread == myThread) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e){ } } } 在循环体中,Clock类首先把自己重画一次,然后让这个线程睡眠1秒。 Clock重画自己时实际上调用的就是Applet的paint()方法。源代码如下: public void paint(Graphics g) { Date now = new Date(); g.drawString(now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), 5, 10); }