java中sleep与wait方法研究探讨

蹲街弑〆低调 提交于 2020-03-02 02:13:57

1.sleep与wait方法的区别

这个在面试题目中经常出现,比较全的答案如下:  
 a.sleep是Thread的静态方法,可以睡眠当前调用者进程,而wait是Object里面的方法。    
 b.sleep不释放锁,而wait释放锁,使得其他线程可以使用同步方法或者同步控制块(**但是注意sleep和wait都释放出cpu的使用权**)。  
 c.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)  
  synchronized(x){   x.notify()   //或者wait()  }  
 d.sleep方法要处理异常,而wait不用处理异常。

其实最本质的区别的sleep不释放锁,而wait释放锁。示例:

public class TestSynchronized   
{    
    public void test1()   
    {    
         synchronized(this)   
         {    
              int i = 5;    
              while( i-- > 0)   
              {    
                   System.out.println(Thread.currentThread().getName() + " : " + i);    
                   try   
                   {    
                        Thread.sleep(500);  //sleep并不释放对象锁  
                   }   
                   catch (InterruptedException ie)   
                   {    
                   }    
              }    
         }    
    }    

    public synchronized void test2()   
    {    
         int i = 5;    
         while( i-- > 0)   
         {    
              System.out.println(Thread.currentThread().getName() + " : " + i);    
              try   
              {    
                   Thread.sleep(500);   //sleep并不释放对象锁   
              }   
              catch (InterruptedException ie)   
              {    
              }    
         }    
    }    

    public static void main(String[] args)   
    {    
         final TestSynchronized myt2 = new TestSynchronized();    
         Thread test1 = new Thread(  new Runnable() {  public void run() {  myt2.test1();  }  }, "test1"  );    
         Thread test2 = new Thread(  new Runnable() {  public void run() { myt2.test2();   }  }, "test2"  );    
         test1.start();;    
         test2.start();      
    }   

}

Java代码 收藏代码

test2 : 4  
test2 : 3  
test2 : 2  
test2 : 1  
test2 : 0  
test1 : 4  
test1 : 3  
test1 : 2  
test1 : 1  
test1 : 0

如果将test1和test2里面的sleep(500)换成wait(500),结果就如下:

test1 : 4  
test2 : 4  
test2 : 3  
test1 : 3  
test1 : 2  
test2 : 2  
test2 : 1  
test1 : 1  
test2 : 0  
test1 : 0

2.扩充阅读

 Java 线程中的sleep和wait有一个共同作用,停止当前线程任务运行,但他们存在一定的不同,首先我们先看sleep中的构造函数
  sleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
  sleep(long millis, int nanos) Causes the currently executing thread to sleep (cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.
  sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。
  注意sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过t.sleep()让t对象进入sleep,这样的做法是错误的,它只会是使当前线程被sleep 而不是t线程
  wait方法
  void wait(long timeout)
  Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
  void wait(long timeout, int nanos)
  Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.
  wait属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生InterruptedException,效果以及处理方式同sleep()方法。

sleep()方法和wait()方法都成产生让当前运行的线程停止运行的效果,这是它们的共同点。下面我们来详细说说它们的不同之处。

sleep()方法是本地方法,属于Thread类,它有两种定义:

public static native void sleep(long millis) throws InterruptedException;  
public static void sleep(long millis, int nanos) throws InterruptedException {  
    //other code  
}  

其中的参数millis代表毫秒数(千分之一秒),nanos代表纳秒数(十亿分之一秒)。这两个方法都可以让调用它的线程沉睡(停止运行)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE),但这并不表示它马上就会被运行,因为线程调度机制恢复线程的运行也需要时间。调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。上面的连个方法都声明抛出一个InterruptedException类型的异常,这是因为线程在sleep()期间,有可能被持有它的引用的其它线程调用它的interrupt()方法而中断。中断一个线程会导致一个InterruptedException异常的产生,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

为了更好地理解interrupt()效果,我们来看一下下面这个例子:

public class InterruptTest {  
    public static void main(String[] args) {  
        Thread t = new Thread() {  
            public void run() {  
                try {  
                    System.out.println("我被执行了-在sleep()方法前");  
                    // 停止运行10分钟  
                    Thread.sleep(1000 * 60 * 60 * 10);  
                    System.out.println("我被执行了-在sleep()方法后");  
                } catch (InterruptedException e) {  
                    System.out.println("我被执行了-在catch语句块中");  
                }  
                System.out.println("我被执行了-在try{}语句块后");  
            }  
        };  
        // 启动线程  
        t.start();  
        // 在sleep()结束前中断它  
        t.interrupt();  
    }  
}  

运行结果: 我被执行了-在sleep()方法前
我被执行了-在catch语句块中
我被执行了-在try{}语句块后

wait()方法也是本地方法,属于Object类,有三个定义:

public final void wait() throws InterruptedException {  
    //do something  
}  
public final native void wait(long timeout) throws InterruptedException;  
public final void wait(long timeout, int nanos) throws InterruptedException {  
    //do something  
}  

wari()和wait(long timeout,int nanos)方法都是基于wait(long timeout)方法实现的。同样地,timeout代表毫秒数,nanos代表纳秒数。当调用了某个对象的wait()方法时,当前运行的线程就会转入等待状态(WAITING),等待别的线程再次调用这个对象的notify()或者notifyAll()方法(这两个方法也是本地方法)唤醒它,或者到了指定的最大等待时间,线程自动醒来。如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法同样会被Thread类的interrupt()方法中断,并产生一个InterruptedException异常,效果同sleep()方法被中断一样。

第一种解释:

功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步锁.

唤醒方法不同:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起.

第二种解释:

sleep是Thread类的静态方法。sleep的作用是让线程休眠制定的时间,在时间到达时恢复,也就是说sleep将在接到时间到达事件时恢复线程执行,例如:

try{
     System.out.println("I'm going to bed");
     Thread.sleep(1000);
     System.out.println("I wake up");
}catch(IntrruptedException e) {

}

wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者,例如:

//Thread 1

try{
     obj.wait();     //suspend thread until obj.notify() is called
}
catch(InterrputedException e) {
}

第三种解释:

这两者的施加者是有本质区别的. sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制.

而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是 thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但这个流程并没有结束,我一直想去煮饭,但还没被允许, 直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处继续执行.

其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题

在java.lang.Thread类中,提供了sleep(),而java.lang.Object类中提供了wait(),notify()和notifyAll()方法来操作线程,sleep()可以将一个线程睡眠,参数可以指定一个时间。而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!