您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 资本运营 > java scjp线程
目标在完成了本模块的学习后,你应当能够:定义一个线程在一个Java程序中创建若干分离的线程,控制线程使用的代码和数据控制线程的执行,并用线程编写独立于平台的代码描述在多个线程共享数据时可能会碰到的困难使用synchronized关键字保护数据不受破坏使用wait()和notify()使线程间相互通信解释为什么在JDK1.2中不赞成使用suspend()、resume()和stop()方法?第三节线程13.3.1什么是线程?一个关于计算机的简化的视图是:它有一个执行计算的处理机、包含处理机所执行的程序的ROM(只读存储器)、包含程序所要操作的数据的RAM(只读存储器)。在这个简化视图中,只能执行一个作业。一个关于最现代计算机比较完整的视图允许计算机在同时执行一个以上的作业。你不需关心这一点是如何实现的,只需从编程的角度考虑就可以了。如果你要执行一个以上的作业,这类似有一台以上的计算机。在这个模型中,线程或执行上下文,被认为是带有自己的程序代码和数据的虚拟处理机的封装。java.lang.Thread类允许用户创建并控制他们的线程。注-在这个模块中,使用“Thread”时是指java.lang.Thread而使用“thread”时是指执行上下文。13.3.2线程的三个部分线程什么是线程?虚拟处理机线程的三个部分处理机代码数据进程是正在执行的程序。一个或更多的线程构成了一个进程。一个线程或执行上下文由三个主要部分组成一个虚拟处理机CPU执行的代码代码操作的数据代码可以或不可以由多个线程共享,这和数据是独立的。两个线程如果执行同一个类的实例代码,则它们可以共享相同的代码。类似地,数据可以或不可以由多个线程共享,这和代码是独立的。两个线程如果共享对一个公共对象的存取,则它们可以共享相同的数据。在Java编程中,虚拟处理机封装在Thread类的一个实例里。构造线程时,定义其上下文的代码和数据是由传递给它的构造函数的对象指定的。第四节Java编程中的线程13.4.1创建线程本节介绍了如何创建线程,以及如何使用构造函数参数来为一个线程提供运行时的数据和代码。一个Thread类构造函数带有一个参数,它是Runnable的一个实例。一个Runnable是由CPUCodeDataAthreadorexecutioncontext创建线程多线程编程从同一个Runnbale实例派生的多线程线程共享数据和代码。一个实现了Runnable接口(即,提供了一个publicvoidrun()方法)的类产生的。例如:1.publicclassThreadTest{2.publicstaticvoidmain(Stringargs[]){3.Xyzr=newXyz();4.Threadt=newThread(r);5.}6.}7.8.classXyzimplementsRunnable{9.inti;10.11.publicvoidrun(){12.while(true){13.System.out.println(Hello+i++);14.if(i==50)break;15.}16.}17.}首先,main()方法构造了Xyz类的一个实例r。实例r有它自己的数据,在这里就是整数i。因为实例r是传给Thread的类构造函数的,所以r的整数i就是线程运行时刻所操作的数据。线程总是从它所装载的Runnable实例(在本例中,这个实例就是r。)的run()方法开始运行。一个多线程编程环境允许创建基于同一个Runnable实例的多个线程。这可以通过以下方法来做到:Threadt1=newThread(r);Threadt2=newThread(r);此时,这两个线程共享数据和代码。总之,线程通过Thread对象的一个实例引用。线程从装入的Runnble实例的run()方法开始执行。线程操作的数据从传递给Thread构造函数的Runnable的特定实例处获得。13.4.2启动线程CPUCodeData{NewthreadThreadtlnstance?r?ofXyzXyzclass一个新创建的线程并不自动开始运行。你必须调用它的start()方法。例如,你可以发现上例中第4行代码中的命令:t.start();调用start()方法使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。13.4.3线程调度一个Thread对象在它的生命周期中会处于各种不同的状态。下图形象地说明了这点:尽管线程变为可运行的,但它并不立即开始运行。在一个只带有一个处理机的机器上,在一个时刻只能进行一个动作。下节描述了如果有一个以上可运行线程时,如何分配处理机。在Java中,线程是抢占式的,但并不一定是分时的(一个常见的错误是认为“抢占式”只不过是“分时”的一种新奇的称呼而已)。抢占式调度模型是指可能有多个线程是可运行的,但只有一个线程在实际运行。这个线程会一直运行,直至它不再是可运行的,或者另一个具有更高优先级的线程成为可运行的。对于后面一种情形,低优先级线程被高优先级线程抢占了运行的机会。一个线程可能因为各种原因而不再是可运行的。线程的代码可能执行了一个Thread.sleep()调用,要求这个线程暂停一段固定的时间。这个线程可能在等待访问某个资源,而且在这个资源可访问之前,这个线程无法继续运行。所有可运行线程根据优先级保存在池中。当一个被阻塞的线程变成可运行时,它会被放启动线程使用start()方法使线程置于可运行状态NewRunningRunnableOtherwiseBlockedDeadBlockedinobject`swait()poolBlockedinobject`slockpoolSchedulercompletesrun()start()sleep()orjoin()sleep()timeoutorthreadjoin()sorinterupt()interupt()notify()Lockavailablesynchronized()Threadstates回相应的可运行池。优先级最高的非空池中的线程会得到处理机时间(被运行)。因为Java线程不一定是分时的,所有你必须确保你的代码中的线程会不时地给另外一个线程运行的机会。这可以通过在各种时间间隔中发出sleep()调用来做到。1.publicclassXyzimplementsRunnable{2.publicvoidrun(){3.while(true){4.//dolotsofinterestingstuff5.:6.//Giveotherthreadsachance7.try{8.Thread.sleep(10);9.}catch(InterruptedExceptione){10.//Thisthread'ssleepwasinterrupted11.//byanotherthread12.}13.}14.}15.}注意try和catch块的使用。Thread.sleep()和其它使线程暂停一段时间的方法是可中断的。线程可以调用另外一个线程的interrupt()方法,这将向暂停的线程发出一个InterruptedException。注意Thread类的sleep()方法对当前线程操作,因此被称作Thread.sleep(x),它是一个静态方法。sleep()的参数指定以毫秒为单位的线程最小休眠时间。除非线程因为中断而提早恢复执行,否则它不会在这段时间之前恢复执行。Thread类的另一个方法yield(),可以用来使具有相同优先级的线程获得执行的机会。如果具有相同优先级的其它线程是可运行的,yield()将把调用线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行进程,yield()什么都不做。注意sleep()调用会给较低优先级线程一个运行的机会。yield()方法只会给相同优先级线程一个执行的机会。第五节线程的基本控制13.5.1终止一个线程当一个线程结束运行并终止时,它就不能再运行了。可以用一个指示run()方法必须退出的标志来停止一个线程。1.publicclassXyzimplementsRunnable{2.privatebooleantimeToQuit=false;3.4.publicvoidrun(){5.while(!timeToQuit){6....7.}8.//cleanupbeforerun()ends9.}10.11.publicvoidstopRunning(){12.timeToQuit=true;13.}14.}15.16.publicclassControlThread{17.privateRunnabler=newXyz();18.privateThreadt=newThread(r);19.20.publicvoidstartThread(){21.t.start();22.}23.24.publicvoidstopThread(){25.//usespecificinstanceofXyz26.r.stopRunning();27.}28.}在一段特定的代码中,可以使用静态Thread方法currentThread()来获取对当前线程的引用,例如:1.publicclassXyzimplementsRunnable{2.publicvoidrun(){3.while(true){4.//lotsofinterestingstuff5.//Printnameofthecurrentthread6.System.out.println(Thread+7.Thread.currentThread().getName()+8.completed);9.}10.}11.}13.5.2测试一个线程测试一个线程isAlive()sleep()join()有时线程可处于一个未知的状态。isAlive()方法用来确定一个线程是否仍是活的。活着的线程并不意味着线程正在运行;对于一个已开始运行但还没有完成任务的线程,这个方法返回true。13.5.3延迟线程存在可以使线程暂停执行的机制。也可以恢复运行,就好象什么也每发生过一样,线程看上去就象在很慢地执行一条指令。sleep()sleep()方法是使线程停止一段时间的方法。在sleep时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级(b)正在运行的线程因为其它原因而阻塞1.publicclassXyzimplementsRunnable{2.publicvoidrun(){3.while(true){4.//lotsofinterestingstuff5.//Printnameofthecurrentthread6.System.out.println(Thread+7.Thread.currentThread().getName()+8.completed);9.}10.}11.}join()join()方法使当前线程停下来等待,直至另一个调用join方法的线程终止。例如:publicvoiddoTask(){TimerThreadtt=newTimerThread(100);tt.start();...//Dostuffinparallelwiththeotherthreadfor//awhile...//Waithereforthetimerthreadtofinishtry{tt.join();}catch(InterruptedExceptione){//ttcamebackearly}...//Nowcontinueinthisthread...}可以带有一个以毫秒为单位的时间值来调用join方法,例如:voidjoin(longtimeout);其中join()方法会挂起当前线程。挂起的时间或者为timeout
本文标题:java scjp线程
链接地址:https://www.777doc.com/doc-5034888 .html