《面向对象编程导论第八章.ppt》由会员分享,可在线阅读,更多相关《面向对象编程导论第八章.ppt(32页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、面向对象编程导论授课人:宋东峰 第八章 线程本讲概要本讲重点n线程的概念n线程的生命周期nJava中多线程的编程n继承Thread类与使用Runnable接口nThread类的主要方法n线程的同步与死锁4.1 线程及相关概念 n程序:计算机高级语言编写的代码,静态,是应用程序的蓝本。n 进程:是程序的一次动态执行过程,进程包括所要执行的指令和所需的系统资源,不同的进程所占用的系统资源相对独立。n 线程:比进程更小的执行单位,自身不能自动运行,必须栖身于某一进程之中,由该进程触发执行,属于同一进程的线程共享该进程的系统资源。n多进程:系统中多个程序同时执行(多任务)。n多线程:程序(进程)中多个
2、片断同时执行。4.1.1 线程及相关概念 nJava程序执行的过程n 当JVM加载代码,发现main方法之后,就会启动一个线程,这个线程称作“主线程”,该线程负责执行main方法。n 如果main方法中没有创建其他的线程,那么当main方法执行完最后一个语句,JVM就会结束Java应用程序。n 如果main方法中创建了其他线程,那么JVM就要保证每个线程都有机会使用CPU资源。n JVM一直要等到主线程中的所有线程都结束之后,才结束Java应用程序。4.1.2 线程的生命周期n 线程的五个生命周期n 新建:新建的线程处于新建状态。n 就绪:在创建线程后,它将处于就绪状态,排队等待进程调用。n
3、运行:线程获得CPU资源后,就进入运行状态,开始执行。n 阻塞:在线程等待一个事件时(例如输入/输出操作),就处于阻塞状态。n 死亡:线程不再具有继续运行的能力。n 线程完成了自己的任务。n 线程被强迫终止。4.1.2 线程生命周期示意图新建状态新建状态就绪状态就绪状态阻塞状态阻塞状态运行状态运行状态死亡状死亡状态态4.2 基本编程思路n例:class A implements Runnablepublic void run()./线程所需要执行的代码class B public static void main(String arg)Runnable a=new A();Thread t=n
4、ew Thread(a);t.start();/main方法所在线程的执行代码4.2 线程的优先级和调度调度n 当一个在就绪队列中排队的线程被分配到处理器资源而进入运行状态之后,这个线程就称为被“调度”或被线程调度管理器选中了。n 线程调度管理器负责管理线程排队和处理器在线程之间的分配 在java系统中,线程调度依据优先级基础上的“先到先服务”原则。4.2.1线程的优先级和调度调度n Java虚拟机(JVM)中的线程调度器负责管理线程,调度器把线程的优先级分为10个级别。n 优先级使用Thread类中的类常量表示。static int MIN_PRIORITY 值为1static int MA
5、X_PRIORITY 值为10static int NORM_PRIORITY 值为5 int getPriority():返回线程的优先级。void setPriority(int a)可以设置线程优先级。4.2.2 线程的创建 创建线程有两种方法l继承Thread类l实现Runable接口 每个Java程序至少有一个叫做主线程的线程l Thread类的currentThread方法可以获取主线程(或当前线程)。l getName方法可以取得主线程(或当前线程)的名字。l setName方法可以设置线程的名字。4.2.3 线程的创建public class mainthread public
6、 static void main(String args)Thread thread=Thread.currentThread();System.out.println(thread.getName();thread.setName(“main thread”);System.out.println(thread.getName();mainmain thread4.3线程的创建 继承Thread类l 常用构造方法:public Thread()public Thread(String name)public Thread(Runnable target)Thread thread1=new
7、 Thread();Thread thread2=new Thread(“second”);class TestThread extends Threadpublic TestThread(String name)super(name);TestThread thread1=new TestThread(“second”);4.3 线程的创建l Thread类的常用方法u public void start()调用该方法启动线程,使线程从新建状态转入就绪状态并进入就绪队列。u public void run()Thread类中run()方法体为空,编写Thread类的子类时,需要在子类中覆盖父
8、类的run()方法,该方法中包含了对线程的操作。class mythread extends Thread public void run()/*覆盖该方法*/4.3 线程的创建n 需要注意的问题n 程序需要建立自己的线程时,只需要创建一个已定义好的Thread子类的实例就行了。n 当创建的线程调用start()方法开始运行时,run()方法将被自动执行。n 当run()方法执行完毕,线程就释放内存。n 在线程没有结束run()方法前,不赞成让线程再调用start()方法,否则将发生IllegalThreadStateException异常4.3 线程的创建n public static vo
9、id sleep(long millis)n优先级高的线程在它的run()方法中调用sleep方法来使自己放弃处理器资源,休眠一段时间。n public final boolean isAlive()n检查线程是否仍然在运行。n Static Thread currentThread()n 判断当前正在占有CPU的线程。nJoin()守护线程的使用public class LeftAndRightpublic static void main(String args)Lefthand left;Righthand right;left=new Lefthand();/创建线程 right=ne
10、w Righthand();left.start();/线程开始运行后,Lefthand类中run方法被执行 right.start();/线程开始运行后,Righthand类中run方法被执行 class Righthand extends Thread public void run()for(int i=1;i=5;i+)System.out.print(“B”);trysleep(300);catch(InterruptedException e)运行结果:ABBABBABAAclass Lefthand extends Thread public void run()for(int
11、i=1;i=5;i+)System.out.printl(“A”);try sleep(500);catch(InterruptedException e)4.3 实现Runnable接口 实现Runnable接口 l Runnabale接口只有一个方法run(),所有实现Runnable接口的类都必须具体实现run()方法,定义具体操作。class class mythreadmythread implements implements RunnableRunnable public void run()public void run()/*/*实现该方法实现该方法*/l 一个实现了Runn
12、able接口的类实际上定义了一个主线程外的新线程的操作。4.3 实现Runnable接口l public Thread(Runnable target)l public Thread(Runnable target,String name)u 使用Runnable对象创建一个线程对象。u 参数target称为被创建线程的目标对象,创建目标对象的类负责实现Runable接口。class runnable implements Runnable public runnable()Thread thread=new Thread(this,second);public void()4.3 线程的基本
13、控制检查线程l 使用isAlive()方法检查线程是否在活动状态。v 活动状态说明这个线程已经被启动,并不一定正在执行。挂起线程l 使用sleep()来延迟线程的执行。l 通常,线程不是休眠期满后就立即被唤醒(start),重新调度的情况是:u 被唤醒的线程具有更高的优先级。u 正在执行的线程因为其他原因被阻塞。u 程序处于支持时间片的系统中。4.3 线程的基本控制 结束线程l 自然结束:从run()结尾返回l public void interrupt(),当线程阻塞时,会抛出InterruptedException异常,所以往往需要调用public void isInterrupted()
14、方法来判断线程的阻塞状态l 不推荐使用的方法u public final void stop()u public final void suspend()u public final void resume()4.4 数据的完整性线程线程1线程线程2线程线程10资源资源取过来取过来加加1后送回去后送回去withdrwal()withdrwal()透支透支余额余额变量变量4.4 数据的完整性n对共享对象的访问必须同步,叫做条件变量.nJava语言允许通过监视器(有的参考书称其为管程)使用条件变量实现线程同步.n监视器阻止两个线程同时访问同一个条件变量.它的如同锁一样作用在数据上.n线程1进入wi
15、thdrawal方法时,获得监视器(加锁);当线程1的方法执行完毕返回时,释放监视器(开锁),线程2的withdrawal方能进入.withdrawal()线程线程1监视器监视器线程线程24.4 数据的完整性n用synchronized来标识的区域或方法即为监视器监视的部分。n一个类或一个对象由一个监视器,如果一个程序内有两个方法使用synchronized标志,则他们在一个监视器管理之下.n一般情况下,只在方法的层次上使用关键区readwrite监监视视器器线程线程1线程线程24.4 多线程问题-资源协调此处给出的例子演示两个线程在同步限制下工作的情况.class Account stati
16、cs int balance=1000;/为什么用static?statics int expense=0;public synchronized void withdrawl(int amount)if(amount=balance)balance-=amount;expense+=amount;else System.out.println(“bounced:“+amount);4.5 线程同步v 当两个或多个线程同时访问同一个对象,且其中一个线程要修改这个对象,这时可能产生混乱,这就是典型的同步问题。对象的锁定标志l Java可以为每一个对象的实例分配一个标志,称为锁定标志,用来处理同步
17、问题。l 每个线程通过排队等待的方式获得这个锁定标志来独享对象。l synchronized提供了操作这个标志的方法。l 当持有锁定标志的线程运行完synchronized调用包含的语句后,这个标志会被自动返回4.5 线程同步l 同步方法 synchronized()u 标准写法:public void test()synchronized(this).u 简洁写法:public synchronized test().l 例:会计和出纳共同拥有一个账本,他俩都可以使用存取方法对账本进行访问,但不能同时对账本的账目进行访问4.5 多线程问题-资源协调n多线成问题-资源的协调和锁定n死锁问题n如
18、果你的持有一个锁并试图获取另一个锁时,就有死锁的危险.n解决死锁问题的方法:给条件变量施加排序线程线程2pen线程线程1note把把“pen”给我给我,我我才能给你才能给你“note”把把“note”给我给我,我我才能给你才能给你“pen”4.5 多线程问题-资源协调n可能出现的问题:n生产者比消费者快时,消费者会漏掉一些数据没有取到n消费者比生产者快时,消费者取相同的数据.nnotify()和wait()方法用来协调读取的关系.nnotify()和wait()都只能从同步方法中的调用.生产者生产者消费者消费者.共享对象共享对象writeread4.5 多线程问题-资源协调n 使用wait()
19、、notify()和notifyAll()进行线程间的交互n 这种交互是通过队列来实现的。n wait()、notify()和notifyAll()都是Object类中的final方法,被所有的类继承,且不允许重写的方法。public final void wait()当一个线程使用的同步方法中用到某个变量,而此变量又需要其他线程修改后才能符合本线程的需要,那么可以在同步方法中使用wait()方法。使用wait()方法可以中断方法的执行,使本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。4.5 多线程问题-资源协调l public final void notifyAll()u 其它线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方的同时,应当用notifyAll()方法通知所有的由于使用这个同步方法处于等待的线程结束等待,曾被中断的线程就会从刚才的中断处继续执行这个同步方法,并遵循“先中断线继续”的原则。l public final void notify()u 只是通知第一个处于等待状态的线程结束等待,并唤醒它。l 例:模拟两个人排队买票,张某、李某买电影票,售票员只有两张5元的钱,电影票5元一张。张某拿一张20元排在李的前面,李某排拿一张5元买票。