根据上面关于线程状态的介绍我们可以得到下面的线程状态转换图:
BLOCKED与RUNNABLE状态的转换
我们在上面说到:处于BLOCKED状态的线程是因为在等待锁的释放。假如这里有两个线程a和b, a线程提前获得了锁并且暂未释放锁,此时b就处于BLOCKED状态。我们先来看一个例子:
初看之下,大家可能会觉得线程a会先调用同步方法,同步方法内又调用了Thread.sleep()方法,必然会输出TIMED. WAITING, 而线程b因为等待线程a释放锁所以必然会输出BLOCKED。
其实不然,有两点需要值得大家注意,-是在测试方法blockedTest()内还有一个main线程,二是启动线程后执行run方法还是需要消耗-定时间的。 不打断点的情况下,上面代码中都应该输出RUNNABLE。
测试方法的main线程只保证了a,b两个线程调用star()方法(转化为RUNNABLE状态), 还没等两个线程真正开始争夺锁,就已经打印此时两个线程的状态(RUNNABLE) 了。
这时你可能又会问了,要是我想要打印出BLOCKED状态我该怎么处理呢?其实就处理下测试方法里的main线程就可以了,你让它休息一会儿,打断点或者调用Thread .sleep方法就行。
这里需要注意的是main线程休息的时间,要保证在线程争夺锁的时间内,不要等到前一个线程锁都释放了你再去争夺锁,此时还是得不到BL OCKED状态的。我们把上面的测试方法blockedTest()改动一下:
在这个例子中,由于main线程休眠,所以线程a的run()方 法跟着执行,线程b再接着执行。
在线程a执行run()调用testMethod()之后,线程a休眠了2000ms (注意这里是没有释放锁的),main线程休眠完毕,接着b线程执行的时候是争夺不到锁的,所以这里输出:
WAITING状态与RUNNABLE状态的转换
根据转换图我们知道有3个方法可以使线程从RUNNABL E状态转为WAITING状态。我们主要介绍”FObject.wait)和Threadjoin()。Object.wait()调用wait()方法前线程必须持有对象的锁。
线程调用wait)方法时,会释放当前的锁,直到有其他线程调用notlf)ntifyA()方法唤醒等待锁的线程。
需要注意的是,其他线程调用notify()方法只会唤醒单个等待锁的线程,如果有多个线程都在等待这个锁的话不一定会唤醒到之前调用wait()方法的线程。同样,调用notifyAI()方法唤醒所有等待锁的线程之后,也不一定会马上把时间片分给刚才放弃锁的那个线程,具体要看系统的调度。
Threadjoin()
调用join()方法不会释放锁,会一直等待当前线程执行完毕(转换为TERMINATED状态)。
我们再把上面的例子线程启动那里改变一下:
要是没有调用join方法,main线程不管a线程是否执行完毕都会继续往下走。
a线程启动之后马.上调用了join方法,这里main线程 就会等到a线程执行完毕,所以这里a线程打印的状态固定是TERMIATED。
至于b线程的状态,有可能打印RUNNABLE (尚未进入同步方法),也有可能打印TIMED_ WAITING (进入了同步方法)。
TIMED_ WAITING 与RUNNABLE状态转换
TIMED_ WAITING与WAITING状态类似,只是TIMED_ WAITING状态等 待的时间是指定的。
Thread.sleep(long)
使当前线程睡眠指定时间。需要注意这里的“睡眠”只是暂时使线程停止执行,并不会释放锁。时间到后,线程会重新进入RUNNABLE状态。
Object. wait(ong)
wait(long)方法使线程进入TIMED_ WAITING状态。这里的waitlong)方法与无参方法wait)相同的地方是,都可以通过其他线程调用notfy()或otlyAl()方法来唤醒。
不同的地方是,有参方法wait(long)就算其他线程不来唤醒它,经过指定时间long之后它会自动唤醒,拥有去争夺锁的资格。
Thread,join(long)
join(ong)使当前线程执行指定时间,并且使线程进入TIMED_ WAITING状态。
我们再来改一改刚才的示例:
这里调用a. join(1000L),因为是指定了具体a线程执行的时间的,并且执行时间是小于a线程sleep的时间,所以a线程状态输出TIMED. _WAITING。b线程状态仍然不固定(RUNNABL E或BL OCKED).
线程中断
在某些情况下,我们在线程启动后发现并不需要它继续执行下去时,需要中断线程。目前在Java里还没有安全直接的方法来停止线程,但是Java提供了线程中断机制来处理需要中断线程的情况。
线程中断机制是-种协作机制。需要注意,通过中断操作并不能直接终止一个线程,而是通知需要被中断的线程自行处理。
简单介绍下Thread类里提供的关于线程中断的几个方法:
Threadinterrupt(): 中断线程。这里的中断线程并不会立即停止线程,而是设置线程的中断状态为rue (默认是fase) ;
Thread interrupted(): 测试当前线程是否被中断。线程的中断状态受这个方法的影响,意思是调用一次使线程中断状态设置为true,连续调用两次会使得这个线程的中断状态重新转为false;
Thread,isinterrupted(): 测试当前线程是否被中断。与上面方法不同的是调用这个方法并不会影响线程的中断状态。
在线程中断机制里,当其他线程通知需要被中断的线程后,线程中断的状态被设置为true,但是具体被要求中断的线程要怎么处理,完全由被中断线程自己而定,可以在合适的实际处理中断请求,也可以完全不处理继续执行下去。