《跨平台程序设计语言》课件-第10章 多线程_第1页
《跨平台程序设计语言》课件-第10章 多线程_第2页
《跨平台程序设计语言》课件-第10章 多线程_第3页
《跨平台程序设计语言》课件-第10章 多线程_第4页
《跨平台程序设计语言》课件-第10章 多线程_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

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

文档简介

第10章多线程1.多线程程序主讲人:_________

多线程程序publicclassExample01{publicstaticvoidmain(String[]args){ MyThread01myThread=newMyThread01();//创建MyThread01实例对象 myThread.run();//调用MyThread01类的run()方法 while(true){//该循环是一个死循环,打印输出语句 System.out.println("Main方法在运行"); }}}classMyThread01{publicvoidrun(){ while(true){//该循环是一个死循环,打印输出语句 System.out.println("MyThread类的run()方法在运行"); }}}在学习多线程之前,先来看一个单线程程序的案例。具体代码如下所示。单线程案例多线程程序运行代码,控制台显示的运行结果如下图所示。运行结果多线程程序由上图可知,程序一直打印“MyThread类的run()方法在运行”,这是因为该程序是一个单线程程序,在调用MyThread01类的run()方法时,遇到定义的死循环中,循环会一直进行。因此,MyThread类的打印语句将被无限执行,而main()方法中的打印语句无法得到执行。如果希望代码两个while循环中的的println语句能够并发执行,就需要实现多线程。运行结果分析多线程程序为了实现多线程,Java提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。在Thread类中提供了一个start()方法用于启动新线程,新线程启动后,JVM会自动调用run()方法,如果子类重写了run()方法便会执行子类中的run()方法。线程类Thread多线程程序publicclassExample02{publicstaticvoidmain(String[]args){ MyThread02myThread=newMyThread02();//创建MyThread02的线程对象

myThread.start();//开启线程 while(true){//通过死循环语句打印输出 System.out.println("main()方法在运行"); }}}classMyThread02extendsThread{

publicvoidrun(){ while(true){//通过死循环语句打印输出 System.out.println("MyThread类的run()方法在运行"); }}}下面通过继承Thread类的方式来实现多线程。具体代码如下所示。多线程案例多线程程序运行代码,控制台显示的运行结果如下图所示。由图可知,两个循环中的语句都有输出,说明程序实现了多线程。运行结果单线程和多线程的区别从图可以看出,单线程的程序在运行时,会按照代码的调用顺序执行,而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响。单线程和多线程的区别第10章多线程2.线程同步主讲人:_________

线程安全问题假设售票厅有四个窗口可发售某日某次列车的100张车票,这时100张车票可以看做共享资源,在程序中只能创建一个售票对象,然后开启多个线程去运行同一个售票对象的售票方法,简单来说就是四个线程运行同一个售票程序。上述售票案例中,极有可能碰到“意外”情况,例如一张票被打印多次,或者打印出的票号为0甚至负数。这些“意外”都是由多线程操作共享资源ticket所导致的线程安全问题。模拟上述所说的“意外”情况。假设四个窗口同时出售10张票,并在售票的代码中使用sleep()方法,令每次售票时线程休眠300毫秒。具体代码如下。案例说明案例分析线程安全问题步骤一:定义SaleThread类并实现Runnable接口;定义私有int类型变量tickets,表示总票数,初始值为10;重写run()方法,在run()方法中使用while循环售票;调用sleep()方法使线程休眠300毫秒,用于模拟售票过程中线程的延迟;具体代码如下所示:staticclassSaleThreadimplementsRunnable{privateinttickets=10; //tickets表示总票数:10张票publicvoidrun(){ while(tickets>0){ try{ Thread.sleep(300);//线程休眠300毫秒 }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--); }}}案例实现线程安全问题publicclassExample15{publicstaticvoidmain(String[]args){ SaleThreadsaleThread=newSaleThread();//创建SaleThread对象 //创建并开启四个线程 newThread(saleThread,"线程一").start(); newThread(saleThread,"线程二").start(); newThread(saleThread,"线程三").start(); newThread(saleThread,"线程四").start();}}步骤二:定义main()方法,创建并开启四个线程,用于模拟四个售票窗口。具体代码如下所示:案例实现线程安全问题运行结果从图中可以看出,最后打印售出的票出现了0和负数,这种现象是不应该出现的,原因是在售票程序的while循环中调用了sleep()方法,出现了线程延迟。假设当票号减为1时,线程1获取了CPU执行权,出售1号票,对票号进行判断后,进入while循环,在售票之前调用sleep()方法进入休眠;线程1休眠之后,线程2获取了CPU执行权,会进行售票,由于此时票号仍为1,所以线程2也会进入循环。同理,线程3和线程4也会进入while循环。休眠结束后,四个线程都会继续售票,这样就相当于将票号减了四次,因此结果会出现0和负数这样的票号。线程同步线程安全问题其实就是由多个线程同时处理共享资源所导致的。要想解决线程安全问题,必须保证在任何时刻只能有一个线程访问共享资源。为了实现多个线程处理同一个资源,在Java中提供了同步机制。同步技术是指一个方法或者一段代码,在某一个时刻最多只能被一个线程执行,该线程未执行完该方法或者代码段之前,其他的并发线程必须等待。没有此限制的,则称之为异步(Asynchronization)。在Java程序设计中,采用同步技术实现临界区互斥访问,线程同步与通信常用的接口、类或修饰符见表8.2。在Java程序设计中,为了解决线程同步问题,采用同步方法或者同步块。同步代码块当多个线程使用同一个共享资源时,可以将处理共享资源的代码放在一个使用synchronized关键字修饰的代码块中,这个代码块被称作同步代码块。synchronized(lock){

操作共享资源代码块}在上面的代码中,lock是一个锁对象,它是同步代码块的关键,相当于为同步代码加锁。当某一个线程执行同步代码块时,其他线程将无法执行,进入阻塞状态。当前线程执行完后,再与其他线程重新抢夺CPU的执行权,抢到CPU执行权的线程将进入同步代码块,执行其中的代码。以此循环往复,直到共享资源被处理完为止。同步代码块的语法格式同步代码块使用同步代码块解决线程安全的问题步骤一:修改上节中的案例,将有关tickets变量的操作全部都放到同步代码块中。为了保证线程持续执行,将同步代码块放在死循环中,直到ticket<0时跳出循环。代码如下:classTicket1implementsRunnable{privateinttickets=10;//定义变量tickets,并赋值10

Objectlock=newObject();//定义任意一个对象,用作同步代码块的锁publicvoidrun(){while(true){

synchronized(lock){//定义同步代码块try{Thread.sleep(300);//经过的线程休眠300毫秒}catch(InterruptedExceptione){e.printStackTrace();}if(tickets>0){System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);}else{//如果tickets小于0,跳出循环break;}}}}}同步代码块使用同步代码块解决线程安全的问题步骤二:定义main()方法,创建并开启四个线程,用于模拟四个售票窗口。代码如下所示:publicclassExample16{publicstaticvoidmain(String[]args){Ticket1ticket=newTicket1();//创建Ticket1对象//创建并开启四个线程newThread(ticket,"线程一").start();newThread(ticket,"线程二").start();newThread(ticket,"线程三").start();newThread(ticket,"线程四").start();}}同步代码块运行代码,控制台显示的运行结果如图所示。运行结果从图可以看出,售出的票不再出现0和负数的情况,这是因为售票的代码实现了同步,之前出现的线程安全问题得以解决。同步方法除了修饰代码块,sychronized关键字同样可以修饰方法,被synchronized关键字修饰的方法为同步方法。同步方法和同步代码块一样,同一时刻,只允许一个线程调用同步方法。synchronized关键字修饰方法的具体语法格式如下:synchronized返回值类型方法名([参数1,...]){}同步方法的语法格式同步方法privatesynchronizedvoidsaleTicket(){if(tickets>0){try{Thread.sleep(300);//经过的线程休眠300毫秒}catch(InterruptedExceptione){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);}}使用同步方法解决线程安全的问题步骤一:将售票代码抽取为售票方法saleTicket(),并用synchronized关键字修饰saleTicket()方法。代码如下所示:同步方法//省略main方法//定义Ticket1类实现Runnable接口classTicket1implementsRunnable{privateinttickets=10;publicvoidrun(){while(true){

saleTicket();//调用售票方法 if(tickets<=0){ break; }}}}使用同步方法解决线程安全的问题步骤二:定义Ticket1类实现Runnable接口,在重写的run()方法中的while循环中调用抽取的售票方法saleTicket()。省略定义main()方法的步骤,参考上面代码即可。具体代码如下所示:同步方法运行代码,控制台显示的运行结果如图所示。从图可以看出,同样没有出现0号和负数号的票,说明同步方法实现了和同步代码块一样的效果。运行结果第10章多线程3.线程通信主讲人:_________

线程通信什么是线程通信?线程通信就是线程间相互发送信息为什么要进行线程通信多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据根据共享数据的情况决定自己该怎么做,以及通知其他线程该怎么做线程通信的实际模型生产者消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者生产的数据一般要求:生产者线程生产完数据后唤醒消费者,然后自己等待,消费者消费完数据后唤醒生产者,然后自己等待就是在一个线程进行了规定操作后,就进入等待状态(wait),等待其他0线程执行完他们的指定代码过后再将其唤醒(notify);等待唤醒机制线程通信线程通信常用方法线程通信有若干个生产者,把生产的产品放在一个仓库(缓冲区中),如果缓冲区装满,则生产者等待。有若干个消费者,从仓库中取出产品;如果仓库中没有产品,则消费者等待。在网络中,经常遇到生产者—消费者问题。为了提高处理效率,如启动若干个线程从网络上接受数据,并把它们保存在本地缓冲区中;然后启动若干个线程对缓冲区的数据进行处理,然后保存到数据库等存储空间。如图所示,某个生产者生产一个产品,把它保存到in指定的位置;某个消费者则从指定的位置out获取相应的产品。生产者-消费者问题线程通信案例:模拟手机接电话系统,有电话就接听,没电话就等待线程通信的前提:线程通信通常是多个线程操作同一个共享资源的时候进行线程通信并且要保证线程安全。线程通信//来电提醒线程,负责来电提醒//接听电话线程。负责接听电话//主方法,创建手机对象,执行开机方法publicclassPhone{//实现线程通信:默认没有电话打进来,等待来电提醒

privatebooleanflag=false;publicvoidrun(){//来电提醒线程//接听电话线程}publicstaticvoidmain(String[]args){Phonephone=newPhone();//创建手机对象

phone.run();//执行开机

}}案例实现线程通信

//1.来电提醒线程

newThread(newRunnable(){@Overridepublicvoidrun(){//一直等待来电提醒

try{while(true){synchronized(Phone.this){if(!flag){

System.out.println("请接听电话");flag=true;//唤醒别人,等待自己

Phone.this.notify();

Phone.this.wait();}}}}catch(Exceptione){

e.printStackTrace();}}}).start();//2.接听电话线程

newThread(newRunnable(){@Overridepublicvoidrun(){//一直准备接听电话

try{

温馨提示

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

评论

0/150

提交评论