• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

sleep() wait() yield() join()傻傻风不清楚?

技术杂谈 勤劳的小蚂蚁 3个月前 (01-22) 81次浏览 已收录 0个评论 扫描二维码

功能

sleep()

sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态。可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。

wait()

  wait()方法需要和notify()及notifyAll()两个方法一起介绍,这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用,也就是说,调用wait(),notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。注意,它们都是Object类的方法,而不是Thread类的方法。
  除了使用notify()和notifyAll()方法,还可以使用带毫秒参数的wait(long timeout)方法,效果是在延迟timeout毫秒后,被暂停的线程将被恢复到锁标志等待池。
  wait(),notify()及notifyAll()只能在synchronized语句中使用,但是如果使用的是ReenTrantLock实现同步,该如何达到这三个方法的效果呢?解决方法是使用ReenTrantLock.newCondition()获取一个Condition类对象,然后Condition的await(),signal()以及signalAll()分别对应上面的三个方法。

yield()

  yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。

join()

join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行.

比较

sleep() vs wait()

来自不同的类

这两个方法来自不同的类,sleep是Thread类的方法,而wait是Object类的方法
//Object.java
public class Object {
    public native int hashCode()
    public boolean equals(Object obj)
    public String toString()
    public final native void notify();
    public final native void notifyAll();
    public final void wait()
}
//Thread
class Thread implements Runnable {
    public static native void yield();
    public static native void sleep(long millis);
    …
}

释放锁

执行sleep方法后不会释放锁,而执行wait方法后会释放锁.
package com.hit.learn.concurrencyinaction;

public class TestD {

    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        try {
            Thread.sleep(1000);
            System.out.println(“main thread is work:1s, Thread1 is run and hold lock!”);
        } catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(new Thread2()).start();
    }

    private static class Thread1 implements Runnable {
        @Override
        public void run() {
            System.out.println(“Thread1 started!”);
            synchronized (TestD.class) {
                try {
                    Thread.sleep(5000);
                    //TestD.class.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(“thread1 is over!!!”);
            }
        }
    }

    private static class Thread2 implements Runnable {
        @Override
        public void run() {
            System.out.println(“Thread2 started!”);
            synchronized (TestD.class) {
                System.out.println(“Thread2 hold Lock”);
                //TestD.class.notify();
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(“thread2 is going on….”);
                System.out.println(“thread2 is over!!!”);
            }
        }
    }

}

执行结果如下:
Thread1 started!
main thread is work:1s, Thread1 is run and hold lock!
Thread2 started!
thread1 is over!!!
Thread2 hold Lock
thread2 is going on….
thread2 is over!!!
Thread1先启动,sleep了5s.在这期间启动Thread2 是不能获得锁的,会在Thread2中的  synchronized (TestD.class) {} Block住,等待Thread1释放掉lock之后,才能获得锁继续执行.
package com.hit.learn.concurrencyinaction;

public class TestD {

    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        try {
            Thread.sleep(1000);
            System.out.println(“main thread is work:1s, Thread1 is run and hold lock!”);
        } catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(new Thread2()).start();
    }

    private static class Thread1 implements Runnable {
        @Override
        public void run() {
            System.out.println(“Thread1 started!”);
            synchronized (TestD.class) {
                try {
                    //Thread.sleep(5000);
                    TestD.class.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(“thread1 is over!!!”);
            }
        }
    }

    private static class Thread2 implements Runnable {
        @Override
        public void run() {
            System.out.println(“Thread2 started!”);
            synchronized (TestD.class) {
                System.out.println(“Thread2 hold Lock”);
                TestD.class.notify();
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(“thread2 is going on….”);
                System.out.println(“thread2 is over!!!”);
            }
        }
    }

}

执行结果如下:
Thread1 started!
main thread is work:1s, Thread1 is run and hold lock!
Thread2 started!
Thread2 hold Lock
thread2 is going on….
thread2 is over!!!
thread1 is over!!!
Thread1先启动,wait()了5s.在这期间启动Thread2 是不能获得锁的,不会在Thread2中的  synchronized (TestD.class) {} Block住,notify()之后可以继续执行.

是否需要在同步块中

wait,notify和notifyAll只能在同步方法或同步代码块中调用,而sleep可以在任何地方调用。
    private static class Thread1 implements Runnable {
        @Override
        public void run() {
            System.out.println(“Thread1 started!”);
            try {
                TestD.class.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

sleep() vs yield()

  • sleep()方法给其他线程运行机会时不考虑其他线程的优先级,因此会给低优先级的线程运行的机会;yield()方法只会给相同优先级或更高优先级的线程运行的机会。
  • 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态。
  • sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明任何异常。
  • sleep()方法比yield()方法具有更好的可移植性(跟操作系统CPU调度相关)。
    sleep方法需要参数,而yield方法不需要参数。

notify() vs notifyAll()

先说两个概念:锁池和等待池
  • 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
  • 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中。
然后再来说notify和notifyAll的区别:
  • 如果线程调用了对象的wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
  • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了。

丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:sleep() wait() yield() join()傻傻风不清楚?
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00