线程:sleep()、wait()、yield()和join()方法

来源:互联网 发布:网站数据库对接 编辑:程序博客网 时间:2024/04/28 15:00

   欢迎大家访问我的博客http://blog.csdn.net/mikejaps专注于android ios  app 开发


  1.sleep()和wait()

        这两个方法都可以让调用它的线程沉睡(sleep)/停止运行(wait)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE)。

        public static native void sleep(long millis) throws InterruptedException;   
        public static void sleep(long millis, int nanos) throws InterruptedException 

        public final void wait() throws InterruptedException
        public final native void wait(long timeout) throws InterruptedException;   
        public final void wait(long timeout, int nanos) throws InterruptedException 

        Parameters:
        millis - the length of time to sleep in milliseconds.毫秒数
        nanos - 0-999999 additional nanoseconds to sleep.纳秒数

        调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。
        当调用了某个对象的wait()方法时,当前运行的线程就会转入WAITING状态,等待别的线程再次调用这个对象的notify()或者notifyAll()方法唤醒它,或者到了指定的最大等待时间,线程自动醒来。如果线程调用了某个对象的wait()方法,这个线程就会释放这个对象所持有的同步资源(不会释放其他对象的同步锁)。
  1. package edu.hust.test;
  2. public class ThreadSleep implements Runnable {
  3.     /*
  4.      * 让线程睡眠的理由很多,比如(1)认为该线程运行得太快,需要减缓一下,以便和其他线程协调;(2)查询当时的股票价格,每睡5分钟查询一次,可以节省带宽,而且即时性要求也不那么高。
  5.      * 注意:时间的精确性。线程醒来之后不会马上运行,而要等待cpu给其分配时间片。因此sleep()中指定的时间并不是线程不运行的精确时间!所以不能依赖sleep()方法提供十分精确的定时。
  6.      * 我们可以看到很多应用程序用sleep()作为定时器,实际是不精确的。
  7.      * 
  8.      * 
  9.      * Thread.sleep(5 * 1000)和Thread.currentThread().sleep(5 * 1000)没区别:都表示让当前线程sleep 5秒.
  10.      * 一个是通过类获取静态方法,一个是通过实例对象获得静态方法(sleep()为静态方法).
  11.      * 
  12.      * 注意:sleep并不是Thread的一个STATE
  13.      */
  14.     public void execute() {
  15.         synchronized(this) {
  16.             try {
  17.                 System.out.println(Thread.currentThread().getName() + ", sleep()前");
  18.                 Thread.sleep(1000);
  19.                 System.out.println(Thread.currentThread().getName() + ", sleep()后");
  20.             } catch (InterruptedException e) {
  21.                 System.out.println(Thread.currentThread().getName() + ", 谁把我吵醒了.....");
  22.             }
  23.             //此处如果使用System.err, 会有很意外的结果。System.out和System.err的区别请见blog
  24.             System.out.println(Thread.currentThread().getName() + ", run()结束..进入TERMINATED状态");
  25.         }
  26.     }
  27.     
  28.     public void run() {
  29.         execute();
  30.     }
  31.     
  32.     public static void main(String[] args) throws InterruptedException {
  33.         ThreadSleep threadSleep = new ThreadSleep();
  34.         Thread[] threads = new Thread[5];
  35.         
  36.         System.out.println(Thread.currentThread().getName() + "线程的状态为:" + Thread.currentThread().getState());
  37.         
  38.         for (Thread thread : threads) {
  39.             thread = new Thread(threadSleep);
  40.             thread.start();
  41.             if ("Thread-1".equals(thread.getName()) || "Thread-3".equals(thread.getName()))
  42.                 thread.interrupt();
  43.         }
  44.     }
  45.     /*
  46.      * 某次运行结果:
  47.      * main线程的状态为:RUNNABLE
  48.      * Thread-1, sleep()前
  49.      * Thread-1, 谁把我吵醒了.....
  50.      * Thread-1, run()结束..进入TERMINATED状态
  51.      * 
  52.      * Thread-3, sleep()前
  53.      * Thread-3, 谁把我吵醒了.....
  54.      * Thread-3, run()结束..进入TERMINATED状态
  55.      * 
  56.      * Thread-0, sleep()前
  57.      * Thread-0, sleep()后
  58.      * Thread-0, run()结束..进入TERMINATED状态
  59.      * 
  60.      * Thread-2, sleep()前
  61.      * Thread-2, sleep()后
  62.      * Thread-2, run()结束..进入TERMINATED状态
  63.      * 
  64.      * Thread-4, sleep()前
  65.      * Thread-4, sleep()后
  66.      * Thread-4, run()结束..进入TERMINATED状态
  67.      * 
  68.      * 从运行结果可以得出很多结论, 其中之一是:调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。
  69.      * 
  70.      * */
  71. }

  1. package edu.hust.test;
  2. class MyThread1 implements Runnable {
  3.     private Object obj;
  4.     public MyThread1(Object o) {
  5.         obj = o;
  6.     }
  7.     
  8.     public void run() {
  9.         synchronized (obj) { //这里是给obj对象(也就是str="爱吃土豆")加锁, 如写成synchronized (this), 则表示是给myThread1加锁.
  10.             try {
  11.                 System.out.println("MyThread1进入wait状态");
  12.                 obj.wait();
  13.                 System.out.println("MyThread1被notify");
  14.             } catch (InterruptedException e) {
  15.                 System.err.println("谁把我吵醒了.....");
  16.             }
  17.         }
  18.     }
  19. }
  20. class MyThread2 implements Runnable {
  21.     private Object obj;
  22.     public MyThread2(Object o) {
  23.         obj = o;
  24.     }
  25.     
  26.     public void run() {
  27.         synchronized (obj) {  //这里是给obj对象(也就是str="爱吃土豆")加锁, 如写成synchronized (this), 则表示是给myThread2加锁.
  28.             System.out.println("MyThread2调用notify()方法");
  29.             obj.notify();
  30.         }
  31.     }
  32. }
  33. public class ThreadWait {
  34.     public static void main(String[] args) {
  35.         //错误的写法, 这里myThread1和myThread2操作的是两个不同的对象.
  36.         //Thread myThread1 = new Thread(new MyThread1(new String("爱吃土豆")));
  37.         //Thread myThread2 = new Thread(new MyThread2(new String("爱吃土豆")));
  38.         
  39.         //正确的写法, 这里myThread1和myThread2操作的是同一个对象.
  40.         String str = "爱吃土豆";
  41.         Thread myThread1 = new Thread(new MyThread1(str));
  42.         Thread myThread2 = new Thread(new MyThread2(str));
  43.         myThread1.start();
  44.         myThread2.start();
  45.     }
  46.     
  47.     /*
  48.      * 运行结果:
  49.      * MyThread1进入wait状态
  50.      * MyThread2调用notify()方法
  51.      * MyThread1被notify
  52.      * 
  53.      * 这里使用了synchronized块来包装某个实例对象(String str = "爱吃土豆")的wait()和notify()方法, 这是由于调用这两个方法的时候线程必须获得同步锁.
  54.      * 如果synchronized包装的不是同一个实例对象的wait()和notify()方法, 则表示给wait()和notify()加的锁不是同一把锁,eg:将synchronized(lock)改为synchronized(this).
  55.      * 将会抛出java.lang.IllegalMonitorStateException, 告诉你current thread not owner.
  56.      * 
  57.      * */
  58.     
  59.     /*
  60.      * 摘录:
  61.      * 多线程常用的一些方法: wait(),wait(long),notify(),notifyAll()
  62.      * wait()      是使持有对象锁的线程释放锁;
  63.      * wait(long)  是使持有对象锁的线程释放锁时间为long(毫秒)后,再次获得锁,wait()和wait(0)等价;
  64.      * notify()    是唤醒一个正在等待该对象锁的线程,如果等待的线程不止一个,那么被唤醒的线程由jvm确定;
  65.      * notifyAll   是唤醒所有正在等待该对象锁的线程.
  66.      * 
  67.      * 应该优先使用notifyAll()方法, 因为唤醒所有线程比唤醒一个线程更容易让jvm找到最适合被唤醒的线程.
  68.      * 对于上述方法,只有在当前线程中才能使用,否则报运行时错误java.lang.IllegalMonitorStateException: current thread not owner.
  69.      * 从实现角度来分析:
  70.      * 在线程调用wait()方法时,需要把它放到一个同步段里,否则将会出现"java.lang.IllegalMonitorStateException: current thread not owner"的异常。
  71.      * 
  72.      * */
  73.     
  74. }
  1. package edu.hust.test;
  2. public class ThreadWait2 implements Runnable {
  3.     
  4.     private Object monitor1 = new Object();
  5.     private Object monitor2 = new Object();
  6.     
  7.     public void run() {
  8.         synchronized (monitor1) {
  9.             System.out.println("monitor1被锁住了");
  10.             synchronized (monitor2) {
  11.                 System.out.println("monitor2被锁住了");
  12.                 try {
  13.                     System.out.println("monitor2进入wait()状态");
  14.                     monitor2.wait();
  15.                 } catch (InterruptedException e) {
  16.                     System.out.println("谁把我吵醒了.....");
  17.                 }
  18.             }
  19.         }
  20.     }
  21.     
  22.     public void getMonitor() throws InterruptedException {
  23.         Thread.sleep(3 * 1000); //让main Thread延迟3秒执行, 使myThread获得足够时间进行线程初始化
  24.         synchronized (monitor2) {
  25.             System.out.println("我取得了monitor2");
  26.         }
  27.         
  28.         synchronized (monitor1) {
  29.             System.out.println("我取得了monitor1");
  30.         }
  31.     }
  32.     
  33.     public static void main(String[] args) {
  34.         ThreadWait2 threadWait2 = new ThreadWait2();
  35.         Thread myThread = new Thread(threadWait2);
  36.         myThread.start();
  37.         try {
  38.             threadWait2.getMonitor();
  39.         } catch (InterruptedException e) {
  40.             System.out.println("谁把我吵醒了.....");
  41.         }
  42.     }
  43.     /*
  44.      * 因为wait()方法没有被notify(), 所以程序不会自动结束. 但运行结果不会改变了:
  45.      * monitor1被锁住了
  46.      * monitor2被锁住了
  47.      * monitor2进入wait()状态
  48.      * 我取得了monitor2
  49.      * 
  50.      * 分析:System.out.println("我取得了monitor1")这句话永远不会得到执行, 因为wait()被调用时只释放了monitor2的锁, 并没有释放monitor1的锁.
  51.      * */
  52. }
        2. yield()
        让当前运行Thread放弃其所占用的cpu时间片,以便让其他Thread运行。用yield()方法的目的是让Thread能适当地轮转。但是,并不能保证达到此效果!因为,即使当前Thread放弃时间片,可是还有可能再次被JVM选中!也就是连任

        3. join()
  1. package edu.hust.test;
  2. public class ThreadJoin {
  3.     public void run() {
  4.         System.out.println("普通打印语句1");
  5.         System.out.println("普通打印语句2");
  6.     }
  7.     
  8.     public static void main(String[] args) throws InterruptedException {
  9.         Thread myThread = new Thread() {
  10.             public void run() {
  11.                 try {
  12.                     Thread.sleep(1000);
  13.                 } catch (InterruptedException e) {
  14.                     System.err.println("谁把我吵醒了.....");
  15.                 }
  16.                 System.out.println("线程:" + Thread.currentThread().getName() + " 启动了");
  17.             }
  18.         };
  19.         myThread.start();
  20.         myThread.join();
  21.         
  22.         new ThreadSeq().run();
  23.     }
  24.     /*
  25.      * 没有t.join(), 运行结果为:
  26.      * 普通打印语句1
  27.      * 普通打印语句2
  28.      * 线程:Thread-0 启动了
  29.      * 
  30.      * 加入t.join(), 运行结果为:
  31.      * 线程:Thread-0 启动了
  32.      * 普通打印语句1
  33.      * 普通打印语句2
  34.      * 
  35.      * join():让当前Thread加入到myThread线程的尾部,意味着myThread线程运行结束之前,当前Thread不会运行。使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能
  36.      * */
  37. }
0 0