首页 西电JAVA10_线程

西电JAVA10_线程

举报
开通vip

西电JAVA10_线程线程西安电子科技大学计算机学院王煦metalwing@sina.com课程内容Java概述面向对象程序设计概念Java语言基础Java面向对象特性Java高级特征常用预定义类的使用异常处理I/O线程GUI程序设计Java网络程序设计线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O线程的概念并发的目的提高系统效率简化程序设计多线程是实现并发的一种有效手段多进程并发(多任务操作系统中)多线程并发:一个进程可以通过运行多个线程来并发地执行多项任务Java语言的重要特征是在语言级支持多线程的程...

西电JAVA10_线程
线程西安电子科技大学计算机学院王煦metalwing@sina.com课程内容Java概述面向对象程序设计概念Java语言基础Java面向对象特性Java高级特征常用预定义类的使用异常处理I/O线程GUI程序设计Java网络程序设计线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O线程的概念并发的目的提高系统效率简化程序设计多线程是实现并发的一种有效手段多进程并发(多任务操作系统中)多线程并发:一个进程可以通过运行多个线程来并发地执行多项任务Java语言的重要特征是在语言级支持多线程的程序设计线程与进程(OS角度)进程:内核级的实体包含代码、数据、堆,PCB(进程管理、内存管理、文件管理信息)等进程结构存在于内核空间,用户程序须通过系统调用进行访问或改变线程:用户级的实体线程结构驻留在用户空间,能够被普通的用户级函数组成的线程库直接访问线程独有:寄存器(栈指针,程序计数器)、栈等一个进程中的所有线程共享该进程的状态什么是线程(程序设计角度)线程:进程中的单个顺序执行流多线程:进程中包含多个顺序执行流Java线程模型线程模型:CPU、程序代码和数据的封装体线程的CPU状态CPU执行的代码CPU执行代码过程中操作的数据共享数据(例如堆)独有数据(PC、栈)代码+数据=线程体(决定线程的行为)注意:代码与数据相互独立代码和部分数据可多线程共享线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/OThread类线程模型由java.lang.Thread类进行定义和描述程序中的线程都是Thread类或其子类的实例Thread类的构造方法publicThread(ThreadGroupgroup,Runnabletarget,Stringname);publicThread();publicThread(Runnabletarget);publicThread(ThreadGroupgroup,Runnabletarget);publicThread(Stringname);publicThread(ThreadGroupgroup,Stringname);publicThread(Runnabletarget,Stringname);group:指明该线程所处的线程组(不建议使用)name:线程名称target:提供线程体的对象(由Runnable接口变量引用的实现了Runnable接口的类的对象)线程的创建方法(一)实现Runnable接口定义一个类实现Runnable接口,提供run()方法的实现将该类的一个实例作为参数传递给Thread构造方法,该实例对象提供线程体(代码:run()方法的实现;数据:对象状态)publicclassCountDownimplementsRunnable{ privatestaticintidcnt=1; privatefinalintthreadid=idcnt++; intcounter=3; publicvoidrun(){ while(counter>=0){ try{ Thread.sleep(1000); }catch(Exceptione){e.printStackTrace();} System.out.println("#"+threadid+ (counter>0?"->"+counter:"->run!")); counter--; } } publicstaticvoidmain(String[]args){ Threadt1=newThread(newCountDown()); Threadt2=newThread(newCountDown()); t1.start(); t2.start(); System.out.println("waitingforrun..."); }} //又例:ThreadTest.java线程从Runnable实例的run()方法开始执行线程是Thread类的一个实例线程的创建方法(二)Thread类本身也实现了Runnable接口,因而可通过重写Thread类的子类中的run()方法定义线程行为,并通过创建Thread子类的实例创建线程继承Thread类从Thread类派生子类,并重写其中的run()方法,以定义线程行为创建该子类的对象即创建线程publicclassCountDown2extendsThread{ privatestaticintidcnt=1; privatefinalintthreadid=idcnt++; intcounter=3; publicvoidrun(){ while(counter>=0){ try{ Thread.sleep(1000); }catch(Exceptione){e.printStackTrace();} System.out.println("#"+threadid+ (counter>0?"->"+counter:"->run!")); counter--; } } publicstaticvoidmain(String[]args){ CountDown2t1=newCountDown2(); Threadt2=newCountDown2(); t1.start(); t2.start(); System.out.println("waitingforrun..."); }} //又例:ThreadTest2.java两种线程创建方法比较实现Runnable接口的优点便于用extends继承其它类继承Thread类的优点程序代码更简单publicclassCountDown3{staticintidcnt=1;publicstaticvoidmain(String[]args){newSubThread().start();newThread(newRun()).start();}}classSubThreadextendsThread{privatefinalintthreadid=CountDown3.idcnt++;publicvoidrun(){try{Thread.sleep(1000);System.out.println("#"+threadid);}catch(Exceptione){e.printStackTrace();} }}classParent{publicvoiddoSth(){System.out.println("dosomething...");}}classRunextendsParentimplementsRunnable{privatefinalintthreadid=CountDown3.idcnt++;publicvoidrun(){try{Thread.sleep(1000);System.out.print("#"+threadid+":");doSth();}catch(Exceptione){e.printStackTrace();}}}线程的运行新创建的线程不会自动运行,必须调用线程的start()方法,如:t.start();该方法的调用把线程的虚拟CPU置为可运行(Runnable)状态Runnable状态意味着该线程可以参加调度,被JVM调度运行,但并不意味着线程会立即运行实现了Runnable接口的类是否可以直接使用而不构造Thread对象?线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O线程优先级Thread类有三个有关线程优先级的静态常量MIN_PRIORITY:最低优先级(1)MAX_PRIORITY:最高优先级(10)NORM_PRIORITY:普通优先级(5)MIN_PRIORITY<=线程优先级<=MAX_PRIORITY,数值越大优先级越高线程有缺省优先级,主线程缺省为NORM_PRIORITY子线程继承其父线程(创建子线程的语句执行时所在的线程)的优先级线程优先级获得/设定线程优先级getPriority()/setPriority()方法注意:用户尽可能不要改变线程的优先级如需改变优先级,则一般在run()方法开始处进行设置Java线程优先级与OS线程优先级难以映射,因此可移植的方式是仅使用MIN_PRIORITY、MAX_PRIORITY和NORM_PRIORITY进行优先级设置线程调度策略线程调度:在单个CPU上以某种顺序运行多个线程Java中线程调度策略:基于优先级的抢先式调度允许多个线程可运行,但只有一个线程在运行根据线程优先级,选择高优先级的可运行线程当前线程持续运行,直到以下两种情况之一该线程自行中止(如执行Thread.sleep()调用,或等待访问共享的资源)出现更高优先级线程成为可运行(这时CPU被高优先级线程抢占运行)同一优先级的多个可运行线程可分时轮流运行,也可逐个运行,由JVM而定实际:平台相关,JVM相关线程的基本控制currentThread():获取当前线程引用isAlive():测试线程是否活着sleep():睡眠join():加入一个线程yield():让步以下控制方法已废止,会导致死锁stop()suspend()resume()线程的基本控制currentThread()Thread类的静态方法,返回当前线程的引用isAlive()线程状态未知时,用以确定线程是否活着返回true:线程已启动,且尚未运行结束sleep()用来使当前线程阻塞(睡眠)一段固定的时间。在线程睡眠时间内,将运行其他线程sleep()结束后,线程从阻塞状态进入Runnable状态线程的基本控制线程的基本控制:join()/*在当前线程中执行t.join()方法使当前线程等待,直到线程t结束为止,线程恢复到runnable状态*/publicvoiddoTask(){TimerThreadt=newTimerThread(100);t.start();…//Dostuffinparallelwiththeotherthreadforawhile…//WaitherefortheTimerThread(t)tofinishtry{t.join();}catch(InterruptedExceptione){//ttcamebackearly}…//continueinthisthread…}线程的基本控制:join()classToJoinextendsThread{publicToJoin(Stringnm){super(nm);}publicvoidrun(){try{Thread.sleep(2000);}catch(InterruptedExceptione){}System.out.println(Thread.currentThread().getName()+"awake!");}}classJoinerimplementsRunnable{privateToJointojoin;publicJoiner(ToJoint){this.tojoin=t;}publicvoidrun(){try{this.tojoin.join();}catch(InterruptedExceptione){}System.out.println(this.tojoin.getName()+"joinfinished");}}publicclassTestJoin{publicstaticvoidmain(String[]args){ToJoint1=newToJoin("t1");t1.start();newThread(newJoiner(t1)).start();}} //又例:ThreadJoinTest.java线程的基本控制:yield()yield()调用该方法将CPU让给具有相同优先级的线程若无同优先级的线程是Runnable状态,则什么也不做线程的基本控制:yield()线程的基本控制:结束线程线程完成运行并结束后,将不能再运行线程除正常运行结束(run()方法执行完成)外,还可用其他方法控制使其停止stop():强行终止线程,易造成线程不一致使用标志flag:通过设置flag指明run()方法应该结束publicclassTestStop{ publicstaticvoidmain(String[]args){ Tickt=newTick(); newThread(t).start(); try{Thread.sleep(3000); }catch(Exceptione){} System.out.println("quitingTask..."); t.stopRunning(); }}classTickimplementsRunnable{ privatebooleantimeToQuit=false; publicvoidstopRunning(){timeToQuit=true;} publicvoidrun(){ while(!timeToQuit){ try{Thread.sleep(1000);System.out.println("tick..."); }catch(Exceptione){} } System.out.println("Tickfinished."); }} //又例:ThreadTerminate.java线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O线程并发中的问题多个线程相对执行的顺序不确定,导致执行结果不确定多个线程操作共享数据时,执行结果不确定导致共享数据的一致性被破坏对共享数据操作的并发控制机制称为线程同步线程并发中的问题//一个堆栈类publicclassMyStack{ privateintidx=0; privatechar[]data=newchar[6]; publicvoidpush(charc){ data[idx]=c; idx++;//栈顶指针指向下一个空单元 } publiccharpop(){ idx--; returndata[idx]; }}线程并发中的问题线程a(压栈)线程b(出栈)堆栈s状态时刻t1时刻t2时刻t3//调用s.push(‘r’);data[idx]=‘r’;//恢复运行idx++;/*线程a被抢占idx++;未执行*/...线程a压入的数据”r”丢失。t4时刻pop()会怎样?对象锁与锁语句对象锁:Java中每个标记为synchronized的对象都含有的一个排他锁synchronized:共享数据的标记方法synchronized标记在特定的代码片段(方法)上,这样的代码片段又称临界区共享数据包含在对象中,对象锁与对象一一对应,对象的所有synchronized方法(代码片段)共享对象锁排他线程获得对象锁后才能执行临界区代码片段(即拥有对该对象的操作权)这时,其他任何线程无法获得对象锁,也无法执行临界区代码示例:MyStack类的改进//栈的push,pop操作都采用这种线程同步机制publicclassMyStack{ … publicvoidpush(charc){ synchronized(this){ data[idx]=c; idx++; } } publiccharpop(){ synchronized(this){ idx--; returndata[idx]; } }}线程a(压栈)线程b(出栈)堆栈s状态时刻t1时刻t2时刻t3/*调用s.push(‘r’),获得s的对象锁后运行*/data[idx]=‘r’;/*调用s.pop(),未获得s的对象锁,b到s的lockpool中等待s的对象锁*///恢复运行idx++;/*完成,并交回s的对象锁*///线程a被抢占...时刻t4/*运行pop()得结果r*/...多线程对共享数据进行操作几点说明如果一个方法的整体都在synchronized块中,则可将synchronized关键字放于方法声明中,也就是说:publicsynchronizedvoidmtd(){/*方法体*/}等价于publicvoidmtd(){synchronized(this){/*方法体*/}}考虑,以上两种方式哪种效率更高?几点说明对象锁具有可重入性:允许已拥有某对象锁的线程再次请求并获得该对象锁publicclassReentrant{publicsynchronizedvoida(){b();System.out.println("hereIam,ina()");}publicsynchronizedvoidb(){System.out.println("hereIam,inb()");}}几点说明对共享资源加锁,是通过限制代码对共享资源的访问方式来实现的——不要留给用户绕过临界区代码访问共享资源的机会将作为类成员变量的共享数据设为private的对共享数据的所有访问都必须使用synchronized何时返还对象锁synchronized()语句块执行完毕后在synchronized()语句块中出现exception时持有锁的线程调用该对象的wait()方法。将该线程放入对象的waitpool中,等待某事件的发生几点说明避免死锁死锁是指两个线程同时等待对方持有的锁死锁的避免完全由程序控制可以采用的方法——资源排序在访问多个共享数据对象时,从全局考虑定义一个获得锁的顺序,并在整个程序中都遵守此顺序;释放锁时,要按加锁的反序释放线程间的交互多个线程间不仅需要同步使用共享数据,还需要进行某种协作,一种典型的协作方式是使用共享资源的wait()和notify()方法wait()和notify()线程在synchronized块中调用R.wait()释放共享对象R的对象锁,将自身阻塞并进入R的waitpool,线程调用R.notify(),将共享对象R的waitpool中的一个线程唤醒(移入lockpool),等待R的对象锁notifyAll()将共享对象waitpool中的所有线程都移入lockpool线程间的交互示例--Producer/Consumer/*Producer线程:每隔300ms产生一个字母压入theStack栈中,共200个*/publicvoidrun(){ charc; for(intI=0;I<200;I++){ c=(char)(math.random()*26+’A’); theStack.push(c); try{ Thread.sleep(300); }catch(InterruptedExceptione){} }}示例--Producer/Consumer/*Consumer线程:每隔300ms从theStack栈中取出一个字符,共200个*/publicvoidrun(){ charc; for(intI=0;I<200;I++){ c=theStack.pop(); try{ Thread.sleep(300); }catch(InterruptedExceptione){} }}示例--Producer/Consumer/*堆栈类SyncStack:为保证共享数据一致性,push()与pop()定义为synchronized*/publicclassSyncStack{ privateVectorbuffer=newVector(400,200); publicsynchronizedcharpop(){…}; publicsynchronizedvoidpush(charc){…}}示例--Producer/Consumer/*堆栈类SyncStack:为实现Producer与Consumer之间的同步,加入wait()与notify()*///pop()中加入wait():publicsynchronizedcharpop(){charc;while(buffer.size()==0){ try{this.wait(); }catch(InterruptedExceptione){}}c=((Character)buffer.remove(buffer.size()-1)).charValue();returnc;}示例--Producer/Consumer/*堆栈类SyncStack:为实现Producer与Consumer之间的同步,加入wait()与notify()*///push()中加入notify:publicsynchronizedvoidpush(charc){ this.notify(); CharactercharObj=newCharacter(c); buffer.addElement(charObj);}例:Producer.java/Consumer.java/SyncStack.java/SyncTest.java线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O线程状态与生命周期线程状态new:线程被创建,尚未start()Runnable:线程可以被调度器选中执行Running:线程正在占用CPU执行Dead:run()执行结束,不会再被调度Blocked:线程此后还能运行,但某种条件阻止其运行当前线程调用sleep()进入睡眠状态当前线程调用t.join()等待线程t执行结束当前线程试图执行临界区代码片段但未获得对象锁当前线程调用共享对象的wait()方法线程的概念线程的创建线程调度控制线程同步线程状态与生命周期线程间的管道流I/O常用的输入/输出流:管道流用以实现线程间数据的直接传输管道输入流:PipedReader/PipedInputStream管道输出流:PipedWriter/PipedOutputStream管道流模型管道流的创建将一个线程的输出流与另一线程的输入流连接PipedInputStreampin=newPipedInputStream(); PipedOutputStreampout=newPipedOutputStream(pin);PipedInputStreampin=newPipedInputStream(); PipedOutputStreampout=newPipedOutputStream(); pin.connect(pout);//或pout.connect(pin);管道流示例输入一组单词,先将每个单词逆序,再将所有单词排序,最后将这些单词逆序输出Rhymingwords.java程序处理流程:
本文档为【西电JAVA10_线程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_884192
暂无简介~
格式:ppt
大小:644KB
软件:PowerPoint
页数:0
分类:互联网
上传时间:2017-12-05
浏览量:16