3Sept.2008©NeusoftConfidentialJAVA编程高级——多线程编程多线程编程目标:Java线程机制以及多线程编程的实现本章旨在向学员介绍:1)Java线程模型。2)Java多线程实现的两种方式:接口和继承。3)线程的休眠,中断及优先级。4)线程的同步和死锁教学方法:讲授ppt+上机练习本章要点•多线程简介多线程模型•多线程实现的两种方式实现Runnable接口继承Thread类•线程的属性和控制线程状态及其生命周期线程类的主要方法休眠和中断•多线程同步/通信问题线程同步,锁和死锁多线程简介1多线程实现的两种方式2线程的属性和控制3多线程同步/通信问题4Contents多线程简介进程计算机在执行的程序的实体e.g.一个.class文件一个.exe文件……线程一个程序内部的顺序控制流一个进程中可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索•基本概念进程/线程区别•进程和线程的区别•多进程和多线程每个进程都有独立的代码和数据空间,进程的切换会有很大的开销同一类线程共享代码和数据空间,每个线程有独立运行的栈和程序计数器,线程切换的开销小多进程:在操作系统中能同时运行多个任务(程序)多线程:在同一应用程序中有多个顺序流同时执行Contents多线程简介1多线程实现的两种方式2线程的属性和控制3多线程同步/通信问题4多线程实现的两种方式•多线程的实现(1)创建线程类继承Thread类或实现Runnable接口(2)通过Thread类构造器来创建线程对象Thread()Thread(Runnabletarget)(3)通过start()方法激活线程对象线程运行多线程实现的两种方式•创建线程的两种方式—线程类继承Thread类——java.lang.Thread实现Runnable接口——java.lang.Runnable•run()方法—线程运行体要将一段代码(线程体)在一个新的线程上运行,该代码应该在一个线程类的run()函数中写一个类implementsRunnable接口,且必须覆盖Runnable接口中的run()方法写一个类extendsThread类,且必须重写Thread类的run()方法继承Thread类实现线程类线程类线程调用定义线程类继承Thread类覆盖run()方法publicvoidrun()•继承Thread类ThreadDemo.javaTestThread.java继承Thread类实现线程类•run()与start()TestThread.java实现Runnable接口实现线程类线程类线程调用定义线程类实现Runnable接口线程共享同样的数据和代码覆盖Runnable接口中的唯一的方法publicvoidrun()•实现Runnable接口RunnableDemo.javaTestRunnable.java两种实现方式的比较•两种方式的比较使用Runnable接口可以避免由于JAVA的单继承性带来的局限适合多个相同的程序代码的线程去处理同一资源情况,把线程同程序的代码、数据有效的分离推荐使用实现Runnable接口Contents多线程简介1多线程实现的两种方式2线程的属性和控制3多线程同步/通信问题4线程状态及其生命周期•线程的状态及其生命周期一个Thread对象在它的整个生存期中能以几种不同的状态存在start()—方法使线程处于可以运行的状态,但不一定意味着该线程立即开始运行线程类中的主要方法•线程中的主要方法——java.lang.Thread线程的优先级•线程的优先级Java提供一个线程调度器来监控程序中启动后进入就绪状态的所用线程,线程调度器按照线程的优先级来决定应调度哪个线程来执行•线程的优先级用数字表示,范围从1到10,一个线程缺省的优先级是5Thread.MIN_PRIORITY=1Thread.NORM_PRIORITY=5Thread.MAX_PRIORITY=10•线程优先级方法getPriority()——确定线程的优先级setPriority()——设置线程的优先级线程的休眠•线程的休眠sleep()•让线程中止一段时间的静态方法•Thread.sleep(longmillis)—暂时停止执行millis毫秒•在睡眠期满的瞬间,再次调用该线程不一定会恢复它的执行join()•导致当前线程等待,直到调用这个join方法的线程终止•join()join(longmillis)join(longmillis,intnanos)yield()•为其他可运行的线程提供执行机会•静态方法—Thread.yield()275-14-7275-14-6275-14-5线程的中断•线程的终止自动终止—一个线程完成执行后,不能再次运行手动终止stop()——已过时,基本不用interrupt()——粗暴的终止方式可通过使用一个标志指示run方法退出,从而终止线程——推荐使用线程的高级操作•线程的高级操作Object类中线程的相关方法:voidwait()导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。voidnotify()唤醒在此对象监视器上等待的单个线程。voidnotifyAll()唤醒在此对象监视器上等待的所有线程。Contents多线程简介1多线程实现的两种方式2线程的属性和控制3多线程同步通信问题4同一票号被打印两次打印出0,甚至负数票号线程同步售票程序线程安全Ticket.javaTestSyn.java解决方案—线程同步线程同步•有时两个或多个线程可能会试图同时访问一个资源例如,一个线程可能尝试从一个文件中读取数据,而另一个线程则尝试在同一文件中修改数据在此情况下,数据可能会变得不一致•为了确保在任何时间点一个共享的资源只被一个线程使用,使用了“同步”当一个线程运行到需要同步的语句后,CPU不去执行其他线程中的、可能影响当前线程中的下一句代码的执行结果的代码块,必须等到下一句执行完后才能去执行其他线程中的相关代码块,这就是线程同步synchronized(Object){//要同步的语句}锁synchronizedvoidmethodA(){}锁定方法锁定代码块•实现同步的两种方式•一旦一个包含锁定方法(用synchronized修饰)的线程被CPU调用,其他线程就无法调用相同对象的锁定方法。当一个线程在一个锁定方法内部,所有试图调用该方法的同实例的其他线程必须等待要取得锁的对象锁•实现同步的两种方式—锁定方法使用同步方法未使用同步锁•实现同步的两种方式—锁定代码块使用同步代码块锁•实现同步的两种方式注意事项:受到synchronized保护的程序代码块和方法中,要访问的对象属性必须设定为private,因为如果不设定为private,那么就可以用不同的方式来访问它,这样就达不到保护的效果了锁•优点:可以显示的知道哪些方法是被锁定的•缺点:方法中有些程序时不需要保护的,如果该方法执行会花很长时间,那么其他人就要花较多时间等待锁被归还;只能取得自己对象的锁,有时候程序设计的需求,可能会需要取得其他对象的锁;锁定代码块•实现同步的两种方式—两种方式的优缺点锁定方法•优点:可以针对某段程序代码锁定,不需要浪费时间在别的程序代码上;可以取得不同对象的锁;•缺点:无法显示的得知哪些方法是被锁定的;死锁•死锁乱用synchronized可能会造成系统打死锁(DeadLock)的状况!锁的归还几种方式:基本上执行完锁定的程序代码后,锁就会自动归还;用break语句跳出锁定的语句块,不过这对于写在方法声明的synchronized没有作用;遇到return语句;遇到了异常;本章小结•多线程简介多线程模型•多线程实现的两种方式实现Runnable接口继承Thread类•线程的属性和控制线程状态及其生命周期线程类的主要方法休眠和中断•多线程同步/通信问题线程同步,锁和死锁