| 首页 |
| [目录] | |
9.5螺纹转换程状态解生命周期的一个线程是有价值的线索时,编程。 程可以存在于不同的国家。 仅因为一个线程的启动( )方法已被调用,它并不意味着线程访问的cpu ,可以立即开始执行。 几个因素决定如何将着手。 图9.3显示了国家和过渡中的生命周期的一个线程。
9.3 。 程状态
种方法的线程级提出下一步。 们使用的例子是在随后的章节。
后布尔isalive ( )
种方法可以用来找出一个线程是活的或死的。 程还活着 ,如果它已经开始但尚未终止,也就是说,它不是在死的状态。 后诠释getpriority ( ) 后无效setpriority (国际newpriority ) 一个方法返回的优先权当前线程。 二种方法改变其优先事项。 先设置将是最低的两个值:指定newpriority的最高优先允许该线程。
态无效产量( )
种方法会导致当前线程暂时停止其执行,从而允许其他线程来执行。
态无效睡眠(长期millisec )全interruptedexception
前线程睡在指定的时间之前它反过来在放送。 后无效加入( )全interruptedexception 后无效加入(长期millisec )全interruptedexception 吁任何援引这两种方法的线程将等待并不会返回,直到该线程已经完成了或者是超时后,在指定的时间,分别为。
效中断( )
方法的线程中断它调用。 待通知,睡觉,或阻止为参加完成国家,线程将收到interruptedexception 。 程优先级程分配的优先次序,该线程调度器可以使用,以确定如何线程将如期进行。 程调度器可以使用线程的优先次序,以确定哪些线程得到执行。 程调度主张给cpu时间的线程的最高优先事项随时运行状态。 是不一定的线程一直是时间最长的现成的运行状态。 重依赖线程的优先事项的行为的程序可以使程序unportable跨平台,因为线程调度主机平台杁依赖性。 点是整数值从1 (最低优先考虑不断线。 min_priority )到10 (最高优先重视不断thread.max_priority ) 。 默认优先级为5 ( thread.norm_priority ) 。 程的优先级继承其母公司线程。 先权的线程可以设置使用setpriority ( )方法和阅读使用getpriority ( )方法,这两者都是定义在线程级。 面的代码设置的优先级的线程mythread到最低的两个值:最高优先事项和当前优先递增到下一个级别:
mythread.setpriority ( math.min ( thread.max_priority , mythread.getpriority ( ) +1 ) ) ;
程调度度中的jvm的实现通常采用的两个战略如下:
当指出,线程调度程序的执行情况和平台相关,因此,如何将预定线程是难以预测的,至少从平台,平台上。 行和高产开始( )方法被称为,线程开始生活在现成的运行状态。 旦现成的运行状态,有资格的线程运行,就是在等待它的又得到cpu时间。 程调度会决定哪些线程运行多长时间。 图9.4显示了过渡之间随时运行和运行状态。 用静态方法产量( )中定义的线程类,会造成当前线程在运行状态过境的现成的运行状态,从而放弃了cpu 。 后线程的摆布线程调度何时将再次运行。 果没有线程等待在现成的运行状态,该线程继续执行。 果有其他线程在现成的运行状态,它们的优先考虑确定哪些线程得到执行。 9.4 。 行和高产
过调用静态方法收益率( ) ,正在运行的线程让其他线程在现成的运行状态有机会运行。 个典型的例子的情况下可能是有用的当用户提供了一些命令启动cpu密集型计算,并可以选择取消它通过点击取消按钮。 果猪的计算线程的cpu和用户点击取消按钮,有机会,它可能需要一段时间之前,线程监控用户输入也获得了这一机会运行,并采取适当行动,以制止计算。 程运行的这样一个计算应计算在递增,收益率之间的增量,让其他线程运行。 明了这一点以下运行( )方法: 共无效运行( ) ( 试( ( !做( ) ) ( dolittlebitmore ( ) ; thread.yield ( ) ; / /当前线程产量 ) )赶上( interruptedexception五) ( docleaningup ( ) ; ) ) 觉和起床9.5 。 觉和起床
用静态方法睡眠( )的线程级将导致当前正在运行的线程暂停其执行和过境的睡眠状态。 方法不放弃任何锁,该线程可能。 程将睡眠至少指定的时间在其论点,然后过渡到现成的运行状态,它反过来又运行。 果一个线程被中断睡觉时,它会抛出一个interruptedexception时awakes ,并得到执行。 serveral重载版本的睡眠( )方法的线程级。 用睡眠( )方法中说明的例子9.1 , 9.2和9.3 。 待和通知待和通知提供的通信手段之间的线程同步的对象相同的 (见第9.4节 ,第359页) 。 程执行等( ) ,并通知( ) (或notifyall ( ) )方法对共享对象用于这一目的。 些最后的方法中定义的对象类,因此,所继承的所有物件。 些方法只能被处决的对象,其拥有的线程锁定,否则,调用将导致illegalmonitorstateexception 。 后无效等待(长期超时)全interruptedexception 后无效等待(长期超时,诠释的nano )全interruptedexception 后无效等待( )全interruptedexception 程调用等待( )方法的对象的锁它。 程被加入到等待的对象。 后无效的通知( ) 后无效notifyall ( ) 程调用通知方法的对象的锁持有通知线程(县)表示,正在等待的对象。 程之间的通讯提供便利,等待和通知,就说明了这一点数字9.6和9.7 。 程通常所称的等待( )方法的对象的锁,因为它拥有一个条件,继续执行没有满足。 程使运行状态和过境的待通知状态。 们在等待此条件下发生。 程放弃所有权的对象锁。 9.6 。 待和通知
9.7 。 程通信
渡到待通知国家和放弃对象锁完成作为一个原子 (非interruptable )作业。 释放锁的共享对象的线程允许其他线程运行和执行同步代码相同的对象后,收购其锁定。 注意,等待线程不放弃任何其它物体上的锁,它可能举行,只是说该对象上的等待( )方法被调用。 些物体的其他锁仍然锁定的线程正在等待。 一个物件都有一套包含等待线程等待通知。 程的待通知国家是根据对象的等待( )方法,他们援引。 图9.7显示了线程吨1 ,首先获得一个锁的共享对象,然后调用等待( )方法的共享对象。 放弃对象锁和1吨的线程等待获得通知。 然线程等待1吨, 2吨另一个线程可以获取锁的共享对象为自己的目的。 程的待通知国家可惊醒了发生的任何一个,这三个事件:
知引通知( )方法的对象唤醒一个线程正在等待的锁此对象。 择一个线程唤醒取决于线程执行的政策的jvm 。 得到通知 ,等待第一个线程的封锁过境为锁定收购国家获得锁定的对象,而不是直接向现成的运行状态。 程也从等待的对象。 注意,锁定的对象是没有放弃当线程调用通知通知( )方法。 知线程放弃锁定在自己的自由裁量权,并唤醒线程将无法运行,直到通知线程放弃对象锁。 线程获得通知的对象锁,它是启用的执行,等待在现成的运行状态反过来执行一次。 后,当它得到执行,呼叫等待( )方法返回的线程可以继续执行。 图9.7我们看到线程吨2不放弃锁定的对象时,调用通知( )方法。 纹吨1被迫等待的封锁换锁收购状态。 是没有任何特权,必须与任何其他线程等待锁收购。 吁通知( )方法没有任何后果,如果没有线程在等待的对象。 此相反的通知( )方法, notifyall ( )方法唤醒所有线程在等待设置的共享对象。 们将所有过境的封锁换锁购置国家和争夺的对象锁定为解释过。 时等待( )调用的时候指定的线程应该等待超时之前,如果还没有醒悟的解释过。 醒线程的竞争通常方式执行一次。 注意,唤醒线程已经没有办法知道它是否超时或惊醒了一个通知方法。 断意味着另一个线程调用中断( )方法等待线程。 程的唤醒启用如前所述解释,但如果当唤醒线程最后也获得了这一机会运行,返回的等待( )调用将导致interruptedexception 。 就是为什么代码援引等待( )方法必须准备处理这一检查例外。 如9.4等待和通知
流的stackimpl (私人对象[ ] stackarray ;私营动荡国际topofstack ; stackimpl (国际能力) ( stackarray =新的对象[能力] ; topofstack = -1 ; )公共同步对象弹出( ) ( system.out.println ( thread.currentthread ( ) + “ :出现” ) ;而( isempty ( ) ) ( system.out.println尝试( thread.currentthread ( ) + “ :等待弹出” ) ;等待( ) ; / / ( 1 ) )赶上( interruptedexception五) ( )对象目标= stackarray [ topofstack ] ; stackarray [ topofstack - ] =无效; system.out.println ( thread.currentthread ( ) + “ :通知后,弹出” ) ;通知( ) ; / / ( 2 )返回目标; )公共同步无效推动(对象元) ( system.out.println ( thread.currentthread ( ) + “ :推进” ) ;而( isfull ( ) ) ( system.out.println尝试( thread.currentthread ( ) + “ :等待推” ) ;等待( ) ; / / ( 3 ) )赶上( interruptedexception五) ( ) stackarray [ + + topofstack ] =元; system.out.println ( thread.currentthread ( ) + “ :通知后推“ ) ;通知( ) ; / / ( 4 ) )公共布尔isfull ( ) (返回topofstack ” = stackarray.length -1 ; )公共布尔isempty ( ) (返回topofstack “ 0 ; ) )抽象类stackuser延伸线( / / ( 5 )栈用户保护stackimpl堆栈; / / ( 6 ) stackuser (字符串threadname , stackimpl栈) (超级( threadname ) ; this.stack =堆栈; system.out.println (本) ; setdaemon (真实) ; / / ( 7 )守护程序线程开始( ) ; / / ( 8 )启动该线程。 ) )类stackpopper延伸stackuser ( / / ( 9 )波普尔stackpopper (字符串threadname , stackimpl栈) (超级( threadname ,栈) ; )公共无效运行( ) (而(真正) stack.pop ( ) ; ) )类stackpusher延伸stackuser ( / / ( 10 )推stackpusher (字符串threadname , stackimpl栈) (超级( threadname ,栈) ; )公共无效运行( ) (而(真正) stack.push (新的整数( 1 ) ) ; ) ) (公共类waitandnotifyclient主要公共静态无效(字符串[ ] args )全interruptedexception ( / / ( 11 ) stackimpl堆栈=新stackimpl ( 5 ) ;新stackpusher ( “ a ”类,堆) ;新stackpusher ( “ b ”的,栈) ;新stackpopper ( “ c ”类,堆) ; system.out.println ( “主线程睡觉。 ” ) ; thread.sleep ( 1000 ) ; system.out.println ( “退出主线。 ” ) ; ) ) 能的输出从计划: 纹[一个, 5 ,主要] 程并[ b , 5 ,主要] 纹[中, 5 ,主要] 线睡觉。 ... 纹[一个, 5 ,主要] :推 纹[一个, 5 ,主要] :等待,推动 程并[ b , 5 ,主要] :推 程并[ b , 5 ,主要] :等待,推动 纹[中, 5 ,主要] :突然 纹[中, 5 ,主要] :通知后弹出 纹[一个, 5 ,主要] :通知后推 纹[一个, 5 ,主要] :推 纹[一个, 5 ,主要] :等待,推动 程并[ b , 5 ,主要] :等待,推动 纹[中, 5 ,主要] :突然 纹[中, 5 ,主要] :通知后弹出 纹[一个, 5 ,主要] :通知后推 ... 程并[ b , 5 ,主要] :通知后推 ... 出主线。 ... 范例9.4 , 3个线程操作相同的堆栈。 中两个为推动要素的堆栈,而第三个因素是出现了堆栈。 图为例9.4所示图9.8 。
9.8 。 用户
地topofstack级stackimpl宣布动荡 ,以便读取和写入操作这个变量将获得总价值这个变量,而不是任何副本,在运行时(见4.10节 ,第150页) 。 于线程操作相同的堆栈对象和推动( )和 pop ( )方法的类stackimpl同步 ,这意味着线程同步同一对象。 言之,相互排斥的这些行动是保证在同一堆栈对象。 例如9.4说明如何线程等待由于呼叫等待( )方法的对象,是通知另一个线程调用通知( )方法对同一个对象,为了使第一线,以再次开始投放。 中使用的等待( )调用显示在示例9.4 ( 1 )在同步流行( )方法。 一个线程执行这个方法的stackimpl对象认为,堆栈是空的,它调用等待( )方法,以等待一些线索,推动了第一次关于这个堆栈。 一个使用的等待( )调用显示在( 3 )在同步推进( )方法。 一个线程执行这个方法的stackimpl对象认为,堆栈是全面的,它调用等待( )方法来等待一些线程消除的一个因素首先,为了腾出空间供推动行动的协议栈。 一个线程执行的同步方法推( )就成功地推动stackimpl对象的一个因素的叠加,它要求的通知( )方法在( 4 ) 。 待一套stackimpl对象包含所有等待线程早先所谓的等待( )方法在( 1 )或( 3 )在本stackimpl对象。 个线程从等待设置启用运行。 果此线程正在执行一个弹出操作,它现在有一个机会成功,因为栈是不是空的时刻。 果这是执行一个线程推动行动,它可以再试一次,看看是否有余地的堆栈。 一个线程执行的同步方法弹出( )关于持久性有机污染物stackimpl对象成功的一个因素了栈,它要求的通知( )方法在( 2 ) 。 次假设等待一套stackimpl对象不是空的,一个线程的设定是任意选择并启用。 果通知线程正在执行一个弹出操作,它可以着手看看堆栈仍然有一个因素弹出。 果通知线程正在执行推动运作,它现在有一个成功的机会,因为栈是没有充分的时刻。 注意,等待状态( 1 ) ,在弹出操作执行的循环。 待线程得到通知,不保证有效运行,立竿见影。 此之前得到执行,另一个线程可以同步的协议栈和空它。 果通知线程正在等待弹出堆栈,它现在不正确弹出堆栈,因为条件是在收到通知后没有测试。 环确保条件始终是测试通知后,发送线程回到等待的通知,国家如果条件得不到满足。 了避免类似的危险,推动全栈,等待状态( 3 )为推动执行的操作也是在循环中。 行为,每个线程可以追溯到在输出为例9.4 。 个推动和弹出操作可以追溯到一个序列组成的名称,操作要进行,其次是零个或多个等待消息,和结论的通知后,操作完成。 如,执行两个线程阿推所示的输出程序: 纹[一个, 5 ,主要] :推 纹[一个, 5 ,主要] :等待,推动 ... 纹[一个, 5 ,主要] :通知后推 纹[一个, 5 ,主要] :推 纹[一个, 5 ,主要] :等待,推动 ... 纹[一个, 5 ,主要] :通知后推 程b的表现做一推: 程并[ b , 5 ,主要] :推 程并[ b , 5 ,主要] :等待,推动 ... 程并[ b , 5 ,主要] :通知后推 线程的堆栈ç持久性有机污染物的两倍没有任何等待: 纹[中, 5 ,主要] :突然 纹[中, 5 ,主要] :通知后弹出 ... 纹[中, 5 ,主要] :突然 纹[中, 5 ,主要] :通知后弹出 行动交织,输出清楚地表明,顶推船等待时堆栈充分,只有推后堆栈弹出。 三个线程创建的守护线程。 们的地位是在( 7 ) 。 们将被终止,如果他们还没有完成时的主要用户线程死亡,从而停止执行该计划。 入程可以调用重载方法加入( )的另一个线程以等待其他线程完成其执行,然后才能继续,这就是第一个线程等待第二个线程加入后完成。当前正在运行的线程吨1调用方法加入( )的线程吨2 。 加入( )调用没有任何影响,如果线程吨2已经完成。 果线程吨2仍然活着,那么线程1吨过境的封锁为参加完成的国家。 纹吨1等待在该国之前,对这些事件的发生(参见图9.9 ) :
9.9 。 入线程
例如9.5说明加入的线程。 以下的anotherclient使用反类,它扩展了线程类的实例9.2 。 创建两个线程都能够执行。 线援引加入( )方法反线程 。 果反线程尚未完成,主线过境的封锁为参加完成的国家。 计数器线程完成后,主线程将能够运行。 旦主线程正在运行,它继续执行后, ( 5 ) 。 长线程,可致电isalive ( )方法,以确定是否对其子女线程还活着,在中止之前,本身。 呼吁isalive ( )方法反线程在( 6 )正确的报告, 反线程不是活着。 似的情景transpires之间的主线和反乙线程。 线穿过封锁为参加完成国家两次在最。 如9.5连接线反扩展线程( / *见示例9.2 。 * / ) (公共类anotherclient主要公共静态无效(字符串[ ] args ) (反countera =新的( “对抗” ) ;反counterb =新的( “反乙” ) ;尝试( system.out.println ( “等待儿童线程完成。 ” ) ; countera.join ( ) ; / / ( 5 )如果( ! countera.isalive ( ) ) / / ( 6 ) system.out.println ( “反不是还活着。 ” ) ; counterb.join ( ) ; / / ( 7 )如( ! counterb.isalive ( ) ) / / ( 8 ) system.out.println ( “反乙不能活着。 ” ) ; )赶上( interruptedexception五) (系统。 out.println ( “主线程中断。 ” ) ; ) system.out.println ( “退出主线。 ” ) ; ) ) 能的输出从计划: 纹[对抗, 5 ,主要] 纹[反乙, 5 ,主要] 待孩子线程完成。 答: 0 乙: 0 答: 1 乙: 1 答: 2 乙: 2 答: 3 乙: 3 答: 4 乙: 4 出反答: 抗不是活着。 出反湾 乙不能活着。 出主线。 塞的i / o在运行的线程上执行封锁行动需要的资源(如打电话到一个i / o法) ,将转运到封锁换的i / o状态。 锁行动前必须完成的线程可以着手准备到运行状态。 个例子是一个线程读从标准输入端子,其中块,直到输入提供:
际输入= system.in.read ( ) ;
程终止程可以过境死者国家从运行或随时运行的国家。 世时,该线程完成其运行( )方法,要么回到正常或抛出一个异常。 旦在此状态下,线程不能复活。 没有出路的线程可以再次启用运行,甚至没有要求开始( )方法后,更多的线程对象。 例如9.6显示了典型的情况下线程可以控制一个或多个线程。 作由一个循环体,它的线程执行不断。 应该有可能对其他线程启动和停止工作线程。 功能是由一流的工人 ( 1 ) ,其中有一个私人领域thethread宣布在( 2 )跟踪对象的线程执行其运行( )方法。 的kickstart ( )方法在( 3 )在课堂工作者创造和启动一个线程如果尚未运行。 是不够的,只是调用 start ( )方法的线程已终止。 个新线程创建的对象必须是首次。 终止( )方法在( 4 )集外地thethread为 null 。 注意,这不影响任何线程对象可能已经表明,通过提及thethread 。 运行时系统保持任何这类线程对象,因此,改变它的一个提法并不影响对象。 运行( )方法在( 5 )有一个循环的执行是由一个特殊条件。 试的条件,看是否线程对象命名的参考thethread和执行的线程对象,现在是同一个。 是必然的情况下,如果参考thethread具有相同的参考价值时,它被分配的线程创建和开始的kickstart ( )方法。 条件将是真实的,和身体的循环将执行。 是,如果该值参考thethread已经发生了变化,情况会是假的。 这种情况下,将不执行循环的运行( )方法将完成和线程将终止。 户可以控制线程执行级员工 ,使用的kickstart ( )和终止( )方法。 户端是能够终止线程的运行,开始对下一代的循环体,只需通过改变thethread参考为 null 。 范例9.6 , 工人对象首先是建立在( 8 )和一个线程开始对这个工人物体( 9 ) 。 线调用产量( )方法在( 10 )暂时停止执行,并给出了线程对象的工人有机会运行。 线,当时正在执行一次,终止线程工人物体( 11 ) ,正如前文所述。 个简单的场景可以概括几个线程,共用一个工人对象,可以启动和停止线程的工人对象。 如9.6线程终止
流的工人实施运行( / / ( 1 )私营线程thethread ; / / ( 2 )公共无效的kickstart ( ) ( / / ( 3 )如( thethread ==空) ( thethread =新线程(这) ; thethread.start ( ) ; ) )公共无效终止( ) ( / / ( 4 ) thethread =无效; )公共无效运行( ) ( / / ( 5 ) ,而( thethread == thread.currentthread ( ) ) ( / / ( 6 )系统。 out.println ( “到处在循环。 ” ) ; ) ) ) (公共类控制器主要公共静态无效(字符串[ ] args ) ( / / ( 7 )工人工人=新工人( ) ; / / ( 8 )工人。稳健( ) ; / / ( 9 ) thread.yield ( ) ; / / ( 10 ) worker.terminate ( ) ; / / ( 11 ) ) ) 能的输出从计划: 处在循环。 处在循环。 处在循环。 处在循环。 处在循环。 锁入僵局的情况下是一个线程正在等待一个对象锁的另一个线程持有,这第二个线程正在等待一个对象锁,第一个线程持有。 为每个线程正在等待其他线程放弃锁定,他们都等待着永远留在封锁换锁采集状态。 程被认为陷入僵局 。 局是描绘在图 9月10日。 纹吨1锁定对象澳1 ,但无法获得锁对象o 2的 。 纹吨2锁定对象o 2的 ,但无法获得锁对象澳1 。 们只能着手,如果其中一人放弃锁定的其他人希望,这是永远也不会发生。 9月10日。 局
种情况在图 9月10日实施为例9.7 。 纹表 # t1上( 3 )尝试同步时( 4 )和( 5 ) ,第一次对字符串01 ( 1 )然后在字符串氧气在( 2 ) ,分别为。 程时刻在( 6 )没有相反。 同步在( 7 )及( 8 ) , o2的第一对字符串然后在字符串o1群分别。 锁可能会出现以前的解释。 而,潜在的僵局的情况为例9.7很容易修复。 果两个线程获得锁的物体在同一命令,然后相互锁定的依赖是避免僵局不可能发生。 意味着具有相同的锁,在本( 4 )和( 5 )在( 7 )及( 8 ) 。 般情况下,造成了僵局并不总是很容易地发现,更不用说容易修正。 如9.7死锁
共类deadlockdanger (字符串01 = “锁定” ; / / ( 1 )字符串氧气= “步” ; / / ( 2 )螺纹表# t1 = (新线程( “ printer1 ” ) ( / / ( 3 )公共无效运行( ) (而(真正) (同步( 01 ) ( / / ( 4 )同步(氧) ( / / ( 5 ) system.out.println ( 01 +氧气) ; ) ) ) ) ) ) ;线程时刻= (新线程( “ printer2 ” ) ( / / ( 6 )公共无效运行( ) (而(真正) (同步(氧) ( / / ( 7 )花样( 01 ) ( / / ( 8 ) system.out.println (氧+ 01 ) ; ) ) ) ) ) ) ;公共静态无效主要(字符串[ ] args ) ( deadlockdanger发展学习科=新deadlockdanger ( ) ; dld.t1.start ( ) ; dld.t2.start ( ) ; ) ) 能的输出从计划: ... 锁 锁 调一致 调一致 调一致 ... |
| [目录] | |