第5章 多线程教学设计.docx

上传人:b****2 文档编号:1624876 上传时间:2022-10-23 格式:DOCX 页数:20 大小:130.72KB
下载 相关 举报
第5章 多线程教学设计.docx_第1页
第1页 / 共20页
第5章 多线程教学设计.docx_第2页
第2页 / 共20页
第5章 多线程教学设计.docx_第3页
第3页 / 共20页
第5章 多线程教学设计.docx_第4页
第4页 / 共20页
第5章 多线程教学设计.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

第5章 多线程教学设计.docx

《第5章 多线程教学设计.docx》由会员分享,可在线阅读,更多相关《第5章 多线程教学设计.docx(20页珍藏版)》请在冰豆网上搜索。

第5章 多线程教学设计.docx

第5章多线程教学设计

传智播客

《Java基础入门》

教学设计

 

课程名称:

Java基础教程

授课年级:

2014年级

授课学期:

2014学年第一学期

教师姓名:

某某老师

 

2014年05月09日

课题名称

第5章多线程

计划学时

6课时

内容分析

多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作一个线程,它们会交替执行,彼此间可以进行通信。

本章将针对Java线程的相关知识进行详细地讲解,其中包括线程的创建、线程的生命周期、线程的优先级、线程的同步以及线程的通信等

教学目标及基本要求

要求学生熟悉进程、线程的概念,掌握线程创建的两种方式,线程的生命周期中的五种状态以及五种状态之间的转换,了解线程的调度,线程的安全和同步以及多线程之间的通信。

重点及措施

教学重点:

多线程的概念、线程的生命周期及状态转换、线程的生命周期、多线程通信

难点及措施

教学难点:

线程的生命周期、线程的安全和同步、线程的生命周期及状态转换

教学方式

教学采用教师课堂讲授为主,使用教学PPT讲解

第一课时

(线程概念、线程的创建)

线程概念

✧进程

在一个操作系统中,每个独立执行的程序都可称之为一个进程,也就是“正在运行的程序”。

目前大部分计算机上安装的都是多任务操作系统,即能够同时执行多个应用程序,最常见的有Windows、Linux、Unix等。

✧线程

每个运行的程序都是一个进程,在一个进程中还可以有多个执行单元同时运行,这些执行单元可以看做程序执行的一条条线索,被称为线程。

✧单线程和多线程的区别

在前面章节所接触过的程序中,代码都是按照调用顺序依次往下执行,没有出现两段程序代码交替运行的效果,这样的程序称作单线程程序。

如果希望程序中实现多段程序代码交替运行的效果,则需要创建多个线程,即多线程程序。

多线程程序在运行时,每个线程之间都是独立的,它们可以并发执行,如下图所示。

线程的创建

✧两种创建线程的方式

在Java中,线程的创建方式有两种,具体如下:

●继承Thread类,覆写Thread类的run()方法,示例代码如下:

classMyThreadextendsThread{

publicvoidrun(){

while(true){//通过死循环语句打印输出

System.out.println("MyThread类的run()方法在运行");

}

}

}

●实现Runnable接口,示例代码如下:

classMyThreadimplementsRunnable{

//线程的代码段,当调用start()方法时,线程从此处开始执行

publicvoidrun(){

while(true){

System.out.println("MyThread类的run()方法在运行");

}

}

}

✧两种实现多线程方式比较

实现Runnable接口相对于继承Thread类来说,有如下显著的好处:

1、适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。

2、可以避免由于Java的单继承带来的局限性。

在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么就只能采用实现Runnable接口的方式。

事实上,大部分的多线程应用都会采用第二种方式,即实现Runnable接口。

第二课时

(线程的生命周期、状态转换)

线程的生命周期

线程整个生命周期可以分为五个阶段,具体如下:

●新建状态(New)

创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其它Java对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征。

●就绪状态(Runnable)

当线程对象调用了start()方法后,该线程就进入就绪状态(也称可运行状态)。

处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,能否获得CPU的使用权开始运行,还需要等待系统的调度。

●运行状态(Running)

如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态。

当一个线程启动后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就结束了),当使用完系统分配的时间后,系统就会剥夺该线程占用的CPU资源,让其它线程获得执行的机会。

需要注意的是,只有处于就绪状态的线程才可能转换到运行状态。

●阻塞状态(Blocked)

一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。

线程进入阻塞状态后,就不能进入排队队列。

只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。

●死亡状态(Terminated)

线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入死亡状态。

一旦进入死亡状态,线程将不再拥有运行的资格,也不能再转换到其它状态。

线程的状态转换

线程的不同状态表明了线程当前正在进行的活动。

在程序中,通过一些操作,可以使线程在不同状态之间转换,如下图所示。

线程由运行状态转成阻塞状态和从阻塞状态转成就绪状态的情形如下:

●当线程试图获取某个对象的同步锁时,如果该锁被其它线程所持有,

则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获取到其它线程所持有的锁。

●当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如

果想进入就绪状态就必须要等到这个阻塞的IO方法返回。

●当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程。

●当线程调用了Thread的sleep(longmillis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,线程就会自动进入就绪状态。

●当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态。

第三课时

(线程的调度)

线程的调度

✧概念

程序中的多个线程是并发执行的,某个线程若想被执行必须要得到CPU的使用权。

Java虚拟机会按照特定的机制为程序中的每个线程分配CPU的使用权,这种机制被称作线程的调度。

✧线程调度的模型

线程调度有两种模型,分别是分时调度模型和抢占式调度模型:

●分时调度模型

所谓分时调度模型是指让所有的线程轮流获得CPU的使用权,并且平均分配每个线程占用的CPU的时间片。

●抢占式调度模型

抢占式调度模型是指让可运行池中优先级高的线程优先占用CPU,而对于优先级相同的线程,随机选择一个线程使其占用CPU,当它失去了CPU的使用权后,再随机选择其它线程获取CPU使用权。

✧线程的优先级

在应用程序中,如果要对线程进行调度,最直接的方式就是设置线程的优先级。

优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。

线程的优先级用1~10之间的整数来表示,数字越大优先级越高。

除此职位,还可以使用Thread类中提供的三个静态常量表示线程的优先级,具体如下:

✧线程休眠

如果希望人为地控制线程,使正在执行的线程暂停,将CPU让给别的线程,这时可以使用静态方法sleep(longmillis),该方法可以让当前正在执行的线程暂停一段时间,进入休眠等待状态。

当前线程调用sleep(longmillis)方法后,在指定时间(参数millis)内该线程是不会执行的,这样其它的线程就可以得到执行的机会了。

需要注意的是,sleep()是静态方法,只能控制当前正在运行的线程休眠,而不能控制其它线程休眠。

当休眠时间结束后,线程就会返回到就绪状态,而不是立即开始运行。

✧线程让步

线程让步可以通过yield()方法来实现,该方法和sleep()方法有点相似,都可以让当前正在运行的线程暂停,区别在于yield()方法不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次。

当某个线程调用yield()方法之后,只有与当前线程优先级相同或者更高的线程才能获得执行的机会。

✧线程插队

在Thread类中提供了一个join()方法来实现这个“功能”。

当在某个线程中调用其它线程的join()方法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成后它才会继续运行。

第四课时

(多线程同步、多线程通信)

多线程同步

✧线程安全问题

模拟窗口售票程序,假如共有10张票出售,并在售票的代码中每次售票时线程休眠10毫秒,如下所示。

publicclassExample11{

publicstaticvoidmain(String[]args){

//创建Ticket1对象

SaleThreadsaleThread=newSaleThread();

//创建并开启四个线程

newThread(saleThread,"线程一").start();

newThread(saleThread,"线程二").start();

newThread(saleThread,"线程三").start();

newThread(saleThread,"线程四").start();

}

}

//定义Ticket1类实现Runnable接口

classSaleThreadimplementsRunnable{

privateinttickets=10;//10张票

publicvoidrun(){

while(tickets>0){

try{

Thread.sleep(10);//经过此处的线程休眠10毫秒

}catch(InterruptedExceptione){

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+"---卖出的票"

+tickets--);

}

}

}

运行结果如下图所示。

从上图可以看出,售出的票出现了0、-1、-2这样的票号,这种现象是不应该出现的,因此,上面的多线程程序存在安全问题。

✧同步代码块

线程安全问题其实就是由多个线程同时处理共享资源所导致的。

要想解决上述线程安全问题,必须保证用于处理共享资源的代码在任何时刻只能有一个线程访问。

为了实现这种限制,Java中提供了同步机制。

当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置在一个代码块中,使用synchronized关键字来修饰,被称作同步代码块,其语法格式如下:

synchronized(lock){

操作共享资源代码块

}

上面的代码中,lock是一个锁对象,它是同步代码块的关键。

当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0。

当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 互联网

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1