同步中用wait代替sleep
[一个线程在进入对象的休息室(调用该对象的wait()方法)后会释放对该对象的锁],基于这个原因.
在同步中,除非必要,否则你不应用使用Thread.sleep(long l)方法,因为sleep方法并不释放对象的锁.
这是一个极其恶劣的品德,你自己什么事也不干,进入sleep状态,却抓住竞争对象的监视锁不让其它需
要该对象监视锁的线程运行,简单说是极端自私的一种行为.但我看到过很多程序员仍然有在同步方法
中调用sleep的代码.
看下面的例子:
package debug;
class SleepTest{
public synchronized void wantSleep(){
try{
Thread.sleep(1000*60);
}catch(Exception e){}
System.out.println("111");
}
public synchronized void say(){
System.out.println("123");
}
}
class T1 extends Thread{
SleepTest st;
public T1(SleepTest st){
this.st = st;
}
public void run(){
st.wantSleep();
}
}
class T2 extends Thread{
SleepTest st;
public T2(SleepTest st){
this.st = st;
}
public void run(){
st.say();
}
}
public class Test {
public static void main(String[] args) throws Exception{
SleepTest st = new SleepTest();
new T1(st).start();
new T2(st).start();
}
}
我们看到,线程T1的实例运行后,当前线程抓住了st实例的锁,然后进入了sleep.直到它睡满60秒后
才运行到System.out.println("111");然后run方法运行完成释放了对st的监视锁,线程T2的实例才
得到运行的机会.
而如果我们把wantSleep方法改成:
public synchronized void wantSleep(){
try{
//Thread.sleep(1000*60);
this.wait(1000*60);
}catch(Exception e){}
System.out.println("111");
}
我们看到,T2的实例所在的线程立即就得到了运行机会,首先打印了123,而T1的实例所在的线程仍然
等待,直到等待60秒后运行到System.out.println("111");方法.
所以,调用wait(long l)方法不仅达到了阻塞当前线程规定时间内不运行,而且让其它有竞争需求的线程
有了运行机会,这种利人不损己的方法,何乐而不为?这也是一个有良心的程序员应该遵循的原则.
当一个线程调用wait(long l)方法后,线程如果继续运行,你无法知道它是等待时间完成了还是在wait时被其
它线程唤醒了,如果你非常在意它一定要等待足够的时间才执行某任务,而不希望是中途被唤醒,这里有
一个不是非常准确的方法:
long l = System.System.currentTimeMillis();
wait(1000);//准备让当前线程等待1秒
while((System.System.currentTimeMillis() - l) <1000)//执行到这里说明它还没有等待到1秒
//是让其它线程给闹醒了
wait(1000-(System.System.currentTimeMillis()-l));//继续等待余下的时间.
这种方法不是很准确,但基本上能达到目的.
所以在同步方法中,除非你明确知道自己在干什么,非要这么做的话,你没有理由使用sleep,wait方法足够
达到你想要的目的.而如果你是一个很保守的人,看到上面这段话后,你对sleep方法深恶痛绝,坚决不用sleep
了,那么在非同步的方法中(没有和其它线程竞争的对象),你想让当前线程阻塞一定时间后再运行,应该如何
做呢?(这完全是一种卖弄,在非同步的方法中你就应该合理地应用sleep嘛,但如果你坚决不用sleep,那就这
样来做吧)
public static mySleep(long l){
Object o = new Object();
synchronized(o){
try{
o.wait(l);
}catch(Exception e){}
}
}
放心吧,没有人能在这个方法外调用o.notify[All],所以o.wait(l)会一直等到设定的时间才会运行完成.