第1章 多线程教材_第1页
第1章 多线程教材_第2页
第1章 多线程教材_第3页
第1章 多线程教材_第4页
第1章 多线程教材_第5页
已阅读5页,还剩66页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1章多线程信息科学与技术学院java程序设计课程2/138学习目标1.理解线程的基本概念,掌握创建线程的方法,能进行线程程序设计;2.理解线程的同步与互斥,理解具有同步与互斥关系的线程程序设计。信息科学与技术学院java程序设计课程3/138内容摘要1.1引言1.2线程的概念1.3扩展Thread创建线程1.4实现Runnable创建线程1.5线程的生命周期1.6线程同步1.7没有线程同步的生产者/消费者1.8线程同步情况下的生产者/消费者信息科学与技术学院java程序设计课程4/1381.1引言Java的重要功能之一就是天然地支持多线程。多线程(multithreading)是指一个程序允许同时运行多个任务的能力.在许多系统中多线程是通过调用依赖于系统的过程或函数来实现的。本章将介绍线程的概念以及如何在Java中开发多线程.信息科学与技术学院java程序设计课程5/1381.2线程的概念一个线程(thread)指是程序中完成一个任务的有始有终的执行流。使用Java,可以在一个程序中并发地运行多个线程。这些线程可以同时在多个处理器系统上运行。如下图所示:信息科学与技术学院java程序设计课程6/1381.2线程的概念在单处理器系统上,多个线程分享CPU的时间,操作系统负责给它们调度和分配资源,如图所指示:信息科学与技术学院java程序设计课程7/1381.2线程的概念多线程可以使程序反应更快、交互性更强、执行效率更高。例如,一个好的文字处理允许在输入文字的同时打印或者保存文件。在一些情况下,即使在单处理器系统上,多线程程序的运行速度也要比单线程快。在Java中多线程程序的开发和运行提供了非常好的支持,当程序作为一个application(应用程序)运行时,Java解释器为main方法开始一个线程。当程序作为一个applet运行时,web浏览器开始一个线程来运行applet,信息科学与技术学院java程序设计课程8/1381.2线程的概念在程序中还可以创建附加的线程以执行并发任务。每个线程都是一个对象,它的类实现Runnable接口。这种新对象称为可运行对象(runnableobject)即可以通过扩展Thread类,也可以通过实现Runnable接口来编写多线程程序。信息科学与技术学院java程序设计课程9/1381.3扩展Thread类创建线程Thread类包含创建线程的构造方法,以及控制线程的很多有用方法。要创建并运行一个线程,首先要定义Thread类的一个扩展类。自定义的线程必须覆盖run()方法,该方法告知系统如何执行线程。然后创建一个在线程上运行的对象。下图给出了一个模板。信息科学与技术学院java程序设计课程10/1381.3扩展Thread类创建线程信息科学与技术学院java程序设计课程11/1381.3扩展Thread类创建线程publicclassTestThread{//主要方法

publicstaticvoidmain(String[]args){//创建若干线程对象

PrintCharprintA=newPrintChar('a',100);PrintCharprintB=newPrintChar('b',100);PrintNumprint100=newPrintNum(100);//开始执行这些线程对象

print101.start();printA.start();printB.start();}}信息科学与技术学院java程序设计课程12/1381.3扩展Thread类创建线程classPrintCharextendsThread{privatecharcharToPrint;privateinttimes;publicPrintChar(charc,intt){charToPrint=c;times=t;}publicvoidrun(){for(inti=0;i<times;i++)System.out.print(charToPrint);}}信息科学与技术学院java程序设计课程13/1381.3扩展Thread类创建线程classPrintNumextendsThread{privateintlastNum;publicPrintNum(intn){lastNum=n;}publicvoidrun(){for(inti=1;i<=lastNum;i++){System.out.print(""+i);}}}信息科学与技术学院java程序设计课程14/1381.4实现Runnable接口创建线程问题:扩展Thread类创建线程存在着一个问题,就是如果线程类要继承别的类,就会导致多继承,而这是Java不允许的。所以,Java提供了实现Runnable接口创建线程的方式。Runnable接口是非常简单的,它仅包含run()方法;需要实现该方法,告诉系统如何运行线程。下图给出了一个模板:信息科学与技术学院java程序设计课程15/1381.4实现Runnable接口创建线程信息科学与技术学院java程序设计课程16/1381.4实现Runnable接口创建线程publicclassTestRunnable{//创建若干线程ThreadprintA=newThread(newPrintChar(‘a’,100));ThreadprintB=newThread(newPrintChar(‘a’,100));Threadprint100=newThread(newPrintNum(‘a’,100));//主要方法

publicstaticvoidmain(String[]args){newTestRunnable();}publicTestRunnable(){

print101.start();printA.start();printB.start();}}信息科学与技术学院java程序设计课程17/1381.4实现Runnable接口创建线程classPrintCharimplementsRunnable{privatecharcharToPrint;privateinttimes;publicPrintChar(charc,intt){charToPrint=c;times=t;}publicvoidrun(){for(inti=0;i<times;i++)System.out.print(charToPrint);}}信息科学与技术学院java程序设计课程18/1381.4实现Runnable接口创建线程classPrintNumimplementsRunnable{privateintlastNum;publicPrintNum(intn){lastNum=n;}publicvoidrun(){for(inti=1;i<=lastNum;i++){System.out.print(""+i);}}}信息科学与技术学院java程序设计课程19/1381.4实现Runnable接口创建线程publicclassTestRunnable2{//创建若干线程ThreadprintA=newThread(newPrintChar('a',100));ThreadprintB=newThread(newPrintChar('a',100));Threadprint100=newThread(newPrintNum(100));//主要方法

publicstaticvoidmain(String[]args){TestRunnable2thread=newTestRunnable2();thread.print101.start();thread.printA.start();thread.printB.start();}}信息科学与技术学院java程序设计课程20/1381.5线程的生命周期一个线程任何时候都处于某种线程状态,线程从创建开始,运行直到完成消亡,一般有七种状态:即创建、就绪、运行、等待、休眠、阻塞和死亡等。如下图所示:信息科学与技术学院java程序设计课程21/1381.5线程的生命周期创建start就绪调度运行wait等待时间片完/中断notify/notifyAllsleep休眠休眠时间到I/O请求阻塞I/O操作结束run方法结束或抛出未捕获异常死亡信息科学与技术学院java程序设计课程22/1381.5线程的生命周期例子:多个线程以随机的时间间隔打印。注意:在应用程结束前,main方法(即main线程的执行)就结束了。程序如下:信息科学与技术学院java程序设计课程23/1381.5线程的生命周期publicclassThreadTester{//创建并开始运行线程publicstaticvoidmain(Stringargs[]){PrintThreadthread1,thread2,thread3,thread4;//创建4个打印线程对象thread1=newPrintThread("thread1");thread2=newPrintThread("thread2");thread3=newPrintThread("thread3");thread4=newPrintThread("thread4");信息科学与技术学院java程序设计课程24/1381.5线程的生命周期System.err.println("\nStartingthreads");//开始运行线程thread1.start();thread2.start();thread3.start();thread4.start();System.err.println("Threadsstarted\n");}}//ThreadTester类结束信息科学与技术学院java程序设计课程25/1381.5线程的生命周期//打印线程类.当一个线程运行时,它打印名字//然后,休眠一个随机时间;休眠结束,再打印//名字,接着结束.classPrintThreadextendsThread{privateintsleepTime;//随机时间字段publicPrintThread(Stringname){super(name);//休眠0到5秒sleepTime=(int)(Math.random()*5000);信息科学与技术学院java程序设计课程26/1381.5线程的生命周期//显示名字和休眠时间System.err.println("Name:"+getName()+";sleep:"+sleepTime);}//控制线程执行

信息科学与技术学院java程序设计课程27/1381.5线程的生命周期publicvoidrun(){

try{System.err.println(getName()+"goingtosleep");

Thread.sleep(sleepTime);

}

catch(InterruptedExceptioninterruptedException){System.err.println(interruptedException.toString());

}信息科学与技术学院java程序设计课程28/1381.5线程的生命周期//打印线程名字System.err.println(getName()+"donesleeping");}}//PrintThread类结束信息科学与技术学院java程序设计课程29/1381.6线程同步Java用管程实现同步。每个使用synchronized方法的对象都有一个管程。管程允许一次一个线程运行对象的synchronized方法。当程序调用synchronized方法时,通过将对象锁住来达到这一目的,这种方法又称为上锁。如果有多个synchronized方法,那么一个对象一次只能有一个synchronized方法活动,信息科学与技术学院java程序设计课程30/1381.6线程同步而其它试图调用synchronized方法的线程则必须等待。当synchronized方法运行结束后,管程才会打开该对象的锁并让最高优先级且处于就绪状态的线程调用synchronized方法。正在运行synchronized方法的线程能够知道它不能继续执行,所以它便主动调用wait方法,退出对处理器和管程对象的竞争。这时该线程进行等待状态,而其它线程试图进入信息科学与技术学院java程序设计课程31/1381.6线程同步管程对象。当执行synchronized方法的线程结束运行或满足另一个线程正在等待的条件时,该线程便调用notify方法使处于等待状态的线程重新进入就绪状态。这时原先那个主动调用wait方法进入等待状态且后来由notify唤醒的线程,可以重新获得对象上锁并开始执行。notify方法相当于给等待的线程一个信号,说明线程可以结束等待,因此等待的线程可信息科学与技术学院java程序设计课程32/1381.6线程同步以重新进入管程。如果一个线程调用notifyAll方法,那么所有等待管程的线程都可以重新进入管程(即全部进进入就绪状态)。注意:每次只能有一个线程可以对象上锁,其它试图获得同一把锁的线程会被操作系统阻塞,直到该锁被释放为止。wait、notify和notifyAll方法被Object类的所有子类所继承,因此,任何对象都有管程.信息科学与技术学院java程序设计课程33/1381.6线程同步注意1:等待管程对象的线程必须由notify(或interrupt)方法显示地唤醒,否则它就会永远地等待下去,应致导致死锁;注意2:保确保调用wait方法和调用notify方法是成对出现。注意3:执行synchronized方法产生的锁可能会因为未被释放而导致死锁。当这类异常发生时,java异常机制便会与java同步机制合作,释放相应的同步锁,避免死锁发生。信息科学与技术学院java程序设计课程34/1381.6线程同步注意5:如果线程对一个对象调用wait方法、notify方法或者notifyAll方法,但是没有获得这个对象的锁,便会出错,这会导致IllegalMonitorStateException异常。下面我们来看一看生产者与消费者如何实现。信息科学与技术学院java程序设计课程35/1381.7没有线程同步的生产者/消费者信息科学与技术学院java程序设计课程36/1381.7没有线程同步的生产者/消费者//定义生产者线程类publicclassProduceIntegerextendsThread{//生产者与消费者共享对象

privateHoldIntegerUnsynchronizedsharedObject;信息科学与技术学院java程序设计课程37/1381.7没有线程同步的生产者/消费者//构造方法中初始化

publicProduceInteger(HoldIntegerUnsynchronizedshared){super("ProduceInteger");sharedObject=shared;}信息科学与技术学院java程序设计课程38/1381.7没有线程同步的生产者/消费者//生产者循环10次,每次均调用共享对象设置器

publicvoidrun(){for(intcount=1;count<=10;count++){//先休眠一段随机时间

try{

Thread.sleep((int)(Math.random()*3000));

}信息科学与技术学院java程序设计课程39/1381.7没有线程同步的生产者/消费者//处理休眠期间的InterruptedException异常

catch(InterruptedExceptionexception){System.err.println(exception.toString());

}//休眠结束后调用共享对象的设置器

//进行“产品”设置

sharedObject.setSharedInt(count);}信息科学与技术学院java程序设计课程40/1381.7没有线程同步的生产者/消费者System.err.println(getName()+“完成对数的生产"+“\n结束"+getName());}}//生产者结束处信息科学与技术学院java程序设计课程41/1381.7没有线程同步的生产者/消费者//定义消费者线程类publicclassConsumeIntegerextendsThread{//生产者与消费者共享对象

privateHoldIntegerUnsynchronizedsharedObject;信息科学与技术学院java程序设计课程42/1381.7没有线程同步的生产者/消费者//初始化

publicConsumeInteger(HoldIntegerUnsynchronizedshared){super("ConsumeInteger");sharedObject=shared;}信息科学与技术学院java程序设计课程43/1381.7没有线程同步的生产者/消费者//消费者循环10次,每次均调用共享对象访问器

publicvoidrun(){intvalue,sum=0;do{//先休眠一段随机时间

try{

Thread.sleep((int)(Math.random()*3000));

}信息科学与技术学院java程序设计课程44/1381.7没有线程同步的生产者/消费者//处理休眠期间的InterruptedException异常

catch(InterruptedExceptionexception){System.err.println(exception.toString());

}信息科学与技术学院java程序设计课程45/1381.7没有线程同步的生产者/消费者//休眠结束后调用共享对象的访问器

//以取一个“产品”

value=sharedObject.getSharedInt();sum+=value;}while(value!=10);信息科学与技术学院java程序设计课程46/1381.7没有线程同步的生产者/消费者System.err.println(getName()+“总共享数的总和为:"+sum+“\n结束"+getName());}}//消费者结束处信息科学与技术学院java程序设计课程47/1381.7没有线程同步的生产者/消费者//共享对象类publicclassHoldIntegerUnsynchronized{//共享数据

privateintsharedInt=-1;//非同步地设置共享数据

publicvoidsetSharedInt(intvalue){System.err.println(Thread.currentThread().getName()+"设置新“产品”为"+value);信息科学与技术学院java程序设计课程48/1381.7没有线程同步的生产者/消费者sharedInt=value;}//非同步地访问共享数据

publicintgetSharedInt(){System.err.println(Thread.currentThread().getName()+"访问“产品”:"+sharedInt);信息科学与技术学院java程序设计课程49/1381.7没有线程同步的生产者/消费者returnsharedInt;}}//共享对象类结束处信息科学与技术学院java程序设计课程50/1381.7没有线程同步的生产者/消费者//生产者/消费者测试类.publicclassSharedCell{publicstaticvoidmain(Stringargs[]){//创建共享对象

HoldIntegerUnsynchronizedsharedObject=newHoldIntegerUnsynchronized();信息科学与技术学院java程序设计课程51/1381.7没有线程同步的生产者/消费者//创建线程

ProduceIntegerproducer=newProduceInteger(sharedObject);ConsumeIntegerconsumer=newConsumeInteger(sharedObject);//开始执行线程

producer.start();consumer.start();}}//结束处信息科学与技术学院java程序设计课程52/1381.8线程同步情况下的生产者/消费者信息科学与技术学院java程序设计课程53/1381.8线程同步情况下的生产者/消费者把前节无同步控制HoldIntegerUnsynchronized类改为有同步控制的HoldIntegerSynchronized类.程序如下://定义生产者线程类publicclassProduceIntegerextendsThread{//生产者与消费者共享对象

privateHoldIntegerSynchronizedsharedObject;信息科学与技术学院java程序设计课程54/1381.8线程同步情况下的生产者/消费者//初始化

publicProduceInteger(HoldIntegerSynchronizedshared){super("生产者");sharedObject=shared;}信息科学与技术学院java程序设计课程55/1381.8线程同步情况下的生产者/消费者//生产者循环10次,每次均调用共享对象设置器

publicvoidrun(){for(intcount=1;count<=10;count++){//先休眠一段随机时间

try{

Thread.sleep((int)(Math.random()*3000));

}信息科学与技术学院java程序设计课程56/1381.8线程同步情况下的生产者/消费者//处理休眠期间的InterruptedException异常

catch(InterruptedExceptionexception){System.err.println(exception.toString());

}//休眠结束后调用共享对象的设置器

//进行“产品”设置

sharedObject.setSharedInt(count);}信息科学与技术学院java程序设计课程57/1381.8线程同步情况下的生产者/消费者System.err.println(getName()+"完成生产"+"\n结束"+getName());}}//生产者结束处信息科学与技术学院java程序设计课程58/1381.8线程同步情况下的生产者/消费者//定义消费者线程类publicclassConsumeIntegerextendsThread{//生产者与消费者共享对象

privateHoldIntegerSynchronizedsharedObject;信息科学与技术学院java程序设计课程59/1381.8线程同步情况下的生产者/消费者//初始化

publicConsumeInteger(HoldIntegerSynchronizedshared){super("消费者");sharedObject=shared;}信息科学与技术学院java程序设计课程60/1381.8线程同步情况下的生产者/消费者//消费者循环10次,每次均调用共享对象访问器

publicvoidrun(){intvalue,sum=0;do{//先休眠一段随机时间

try{

Thread.sleep((int)(Math.random()*3000));

}信息科学与技术学院java程序设计课程61/1381.8线程同步情况下的生产者/消费者//处理休眠期间的InterruptedException异常

catch(InterruptedExceptionexception){System.err.println(exception.toString());

}value=sharedObject.getSharedInt();sum+=value;}while(value!=10);信息科学与技术学院java程序设计课程62/1381.8线程同步情况下的生产者/消费者System.err.println(getName()+"消费了的数总计为:"+sum+"\n结束"+getName());}}//消费者结束处信息科学与技术学院java程序设计课程63/1381.8线程同步情况下的生产者/消费者//具有同步功能的共享对象类publicclassHoldIntegerSynchronized{//共享数据

privateintsharedInt=-1;//条件变量

privatebooleanwriteable=true;信息科学与技术学院java程序设计课程64/1381.8线程同步情况下的生产者/消费者//同步地设置共享数据

publicsynchronizedvoidsetSharedInt(intvalue){while(!writeable){//没有轮到生产者

//必须等待

try{wait();

}信息科学与技术学院java程序设计课程65/1381.8线程同步情况下的生产者/消费者//处理等待状态过程产生的中断异常

catch(InterruptedExceptionexception){exception.printStackTrace();

}}System.err.println(Thread.currentT

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论