java高级开发第四章(多线程)

  • 格式:ppt
  • 大小:167.50 KB
  • 文档页数:97

下载文档原格式

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

• 一个代码段被执行,一定是在某个线程上 运行的,代码与线程密不可分,同一段代 码可以与多个线程相关联,在多个线程上 执行的也可以是相同的一段代码,好比多 个火车售票处按相同的操作流程(相当程 序代码)同时售票一样。
• 在上面的代码中,我们使用 Thread.currentThread()静态函数获得该代码 当前执行时对应的那个线程对象。得到当 前线程对象后,我们又调用了线程对象的 getName()方法,取出当前线程的名称字符 串。 • 代码块1处的代码能否运行呢?
• 而TestThread.run则在另一个CPU上运行,但 它们都在向同一个显示器上输出,所以我 们看到两个while循环处的代码同时交替运 行。 • 同样,在代码段run()中,我们也可以通过 线程的静态方法Thread.currentThread()得到 当前线程实例对象。得到当前线程对象后, 我们又调用了线程对象的getName()方法, 取出当前线程的名称字符串 。
小结
• 1. 要将一段代码在一个新的线程上运行, 该代码应该在一个类的run函数中,并且run 函数所在的类是Thread类的子类。倒过来看, 我们要实现多线程,必须编写一个继承了 Thread类的子类,子类要覆盖Thread类中的 run函数,在子类的run函数中调用想在新线 程上运行的程序代码。
• • • • • public class ThreadDemo2 { public static void main(String args[]) { // 调用TestThread类的start函数(从Thread 类继承而来的) • new TestThread2 ().start(); /*run()*/
两种实现多线程方式的对比分析
• • • • • • • • • 我们首先这样编写这个程序: 程序清单:ThreadDemo4.java public class ThreadDemo4 { public static void main(String [] args) { ThreadTest t=new ThreadTest(); t.start(); t.start();
ThreadDemo5
• • • • • • • • • ThreadDemo5.java public class ThreadDemo5 { public static void main(String [] args) { ThreadTest t=new ThreadTest(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start();
• 2. 启动一个新的线程,我们不是直接调用 Thread的子类对象的run方法,而是调用 Thread子类对象的start(从Thread类中继承 的)方法,Thread类对象的start方法将产生 一个新的线程,并在该线程上运行该Thread 类对象中的run方法,根据面向对象的多态 性,在该线程上实际运行的是Thread子类 (也就是我们编写的那个类)对象中的run 方法。
创建多线程两种方法
• 继承Thread类和实现Runnable接口
用Thread类创建线程
• Java的线程是通过java.lang.Thread类来控制 的,一个Thread类的对象代表一个线程,而 且只能代表一个线程,通过Thread 类和它 定义的对象,我们可以获得当前线程对象、 获取某一线程的名称,可以实现控制线程 暂停一段时间等功能
两种实现多线程方式的对比分析
• 既然直接继承Thread类和实现Runnable接口 都能实现多线程,那么这两种实现多线程 的方式在应用上有什么区别呢?我们到底 该用哪一个好呢?
两种实现多线程方式的对比分析
• 为了回答这个问题,我们通过编写一个应 用程序,来进行比较分析。我们用程序来 模拟铁路售票系统,实现通过四个售票点 发售某日某次列车的100张车票,一个售票 点用一个线程来表示。
• 可见,在单线程中,main函数必须等到 TestThread .run函数返回后才能继续往下执 行。而在多线程中,main函数调用 TestThread.start()方法启动了 TestThread.run()函数后,main函数不等待 TestThread.run函数返回就继续运行, TestThread.run函数在一边独自运行,不影 响原来的main函数的运行,这好比将一个 1G的CPU分成了两个500M的CPU,在一个 CPU上运行main函数,
两种实现多线程方式的对比分析
• 经过了这些曲折,这些实验,分析,我们 可以总结出,要实现这个铁路售票模拟程 序,我们只能创建一个资源对象(该对象 中包含要发售的那100 张票),但要创建多 个线程去处理这同一个资源对象,并且每 个线程上所运行的是相同的程序代码。再 回顾一下使用接口编写多线程的过程,大 家应该能够自己写出这个程序了,请大家 自己写完后,再来参看我下面给出的程序 代码。
ຫໍສະໝຸດ Baidu
两种实现多线程方式的对比分析
• 在上面的代码中,我们用ThreadTest类模拟 售票处的售票过程,run方法中的每一次循 环都将总票数减1,模拟卖出一张车票,同 时该车票号打印出来,直到剩余的票数到 零为止。在ThreadDemo4 • 类的main方法中,我们创建了一个线程对 象,并重复启动四次,希望通过这种方式 产生四个线程,结果怎样呢?
• 3. 由于线程的代码段在run方法中,那么该 方法执行完成以后线程也就相应的结束了, 因而我们可以通过控制run方法中的循环条 件来控制线程的终止。
使用Runnable 接口创建多线程
• 从JDK 文档中查看Runnable接口类的帮助, 该接口中只有一个run()方法,当我们使用 Thread(Runnable target)方法创建线程对象 时,需为该方法传递一个实现了Runnable 接口的类对象,这样创建的线程将调用、 那个实现了Runnable接口的类对象中的run() 方法作为其运行代码,而不再调用Thread类 中的run方法了。我们可以将上面的例子改 写成下面这样:
两种实现多线程方式的对比分析
• 从上面结果上,我们看到的结果是每个票 号都被打印了四遍,即四个线程各自卖各 自的100张票,而不是去卖共同的100张票。 这种情况是怎样造成的呢?我们需要的是, 多个线程去处理同一资源,一个资源只能 对应一个对象,在上面的程序中,我们创 建了四个ThreadTest 对象,就等于创建了四 个资源,每个ThreadTest对象中都有100张 票,每个线程在独立地处理各自的资源。
单线程
• 在单线程中,程序代码按调用顺序依次往 下执行,在这种情况下,当主函数调用了 子函数,主函数必须等待子函数返回后才 能继续往下执行,不能实现两段程序代码 同时交替运行的效果。
单线程
• 如果要一程序中实现多段代码同时交替运 行,就需产生多个线程,并指定每个线程 上所要运行的程序代码段,这就是多线程。
用Thread类创建线程
• 将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。
• 计算大于某一规定值的质数的线程可以写 成:
用Thread类创建线程示例1
• • • • • • class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } • }
ThreadDemo2
• 上面的代码让TestThread类继承了Thread类, 也就是TestThread类具有了Thread类的全部 特点,程序没有直接调用TestThread类对象 的run方法,而是调用了该类对象从Thread 类继承来的start方法。运行一下,我们能够 看到两个while循环处的代码同时交替运行. • 这就是我们要讲的多线程。单线程与多线 程的区别,如图所示。
用Thread类创建线程示例1
• 然后,下列代码会创建并启动一个线程: • PrimeThread p = new PrimeThread(143); p.start();
ThreadDemo1
• ThreadDemo1.java
• • • • • • • //代码块1public class ThreadDemo1 { public static void main(String args[]) { new TestThread().run(); while(true) {
• 屏幕上不停地打印出main is running,而不 是main thread is running,这说明代码块1处 的程序没有运行,因为代码块2先于代码块 1运行,且代码块2为无限循环,代码块1永 远没有机会运行。同时,我们也能够看到 当前线程的名称为main。
ThreadDemo2
• package test;
单线程
• 当程序启动运行时,就自动产生了一个线 程,主函数main就是在这个线程上运行的, 当我们不再产生新的线程时,我们的程序 就是单线程的,比如我们以前的例子,它 们都是单线程的。
多线程的优势
• 多线程可以把任务分块执行,分块后可以 同时进行而不用等待。 这样效率更高如下 载文件,通过多线程就可以实现多文件下 载
两种实现多线程方式的对比分析
• 从上面运行结果上,我们发现其实只有一 个线程在运行,且抛出了异常,抛出了异 常的线程main立刻死亡!这个结果告诉我 们:一个线程对象只能启动一个线程,无 论你调用多少遍start()方法,结果都只有一 个线程。
ThreadDemo4
• 我们接着修改ThreadDemo4,在main方法中 创建四个ThreadTest对象: • public class ThreadDemo4 • { • public static void main(String [] args) • { • new ThreadTest().start(); • new ThreadTest().start(); • new ThreadTest().start();
ThreadDemo3
• ThreadDemo3.java • public class ThreadDemo3 • { • public static void main(String args[]) • { • //new TestThread ().start(); • TestThread tt= new TestThread();//创建 TestThread类的一个实例 •
多线程
什么是进程
• 简单地说,在多任务系统中,每个独立执 行的程序称为进程,也就是“正在进行的 程序”。
• 我们现在使用的操作系统一般都是多任务 的,即能够同时执行多个应用程序,如我 们接触最多的Windows、Linux、Unix。
• 实际情况是,操作系统负责对CPU等设备资 源进行分配和管理,虽然这些设备某一时 刻只能做一件事,但以非常小的时间间隔 交替执行多个程序,就可以给人以同时执 行多个程序的感觉。如果我们同时运行记 事本程序的两个实例,这就是两个不同的 进程。
了解线程概念
• 一个进程中又可以包含一个或多个线程, 一个线程就是一个程序内部的一条执行线 索。
Java的线程
• JVM是一个进程,每个进程负责维护一个 主线程和其他子线程,当运行一个main函 数时可以看到系统增加了一个javaw.exe进 程。
Java线程的好处
• 之所以使用线程是因为线程可以共享内存, 因为可以共享内存所以可以把1个任务交由 多个线程并行处理,这样增加了CPU的利用 率, • 其次是因为线程的创建销毁比进程的创建 销毁开销小