前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >sleep() wait() yield() join()傻傻风不清楚?

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

作者头像
Leetcode名企之路
发布2018-12-05 15:47:26
8000
发布2018-12-05 15:47:26
举报
文章被收录于专栏:Leetcode名企之路Leetcode名企之路

功能

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类的方法

代码语言:javascript
复制
//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()
}
代码语言:javascript
复制
//Thread
class Thread implements Runnable {
    public static native void yield();
    public static native void sleep(long millis);
    ...
}

释放锁

执行sleep方法后不会释放锁,而执行wait方法后会释放锁.

代码语言:javascript
复制
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!!!");
            }
        }
    }
}

执行结果如下:

代码语言:javascript
复制
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之后,才能获得锁继续执行.

代码语言:javascript
复制
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!!!");
            }
        }
    }
}

执行结果如下:

代码语言:javascript
复制
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可以在任何地方调用。

代码语言:javascript
复制
    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则不会的例子也就好解释了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Leetcode名企之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 功能
  • sleep()
  • wait()
  • yield()
  • join()
  • 比较
    • sleep() vs wait()
      • 来自不同的类
      • 释放锁
      • 是否需要在同步块中
      • sleep() vs yield()
    • notify() vs notifyAll()
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档