多线程之wait、notify、join、yield、notifyAll

彻底搞懂Java的等待-通知(wait-notify)机制
https://achang.blog.csdn.net/article/details/122790061
并发编程——线程中sleep(),yield(),join(),wait(),notify(),notifyAll()区别

先上一个代码例子再来理解,两个线程交替打印:

public class Test1 {
    //共享对象,用来实现对象锁
    static final Object object = new Object();

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            while (true) {
                synchronized (object) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "执行");
                    object.notify();
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }


        }, "t1");


        Thread t2 = new Thread(() -> {
            while (true) {
                synchronized (object) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "执行");
                    object.notify();
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }, "t2");
        t1.start();
        t2.start();

    }
}

运行结果:

t1执行
t2执行
t1执行
t2执行
t1执行
t2执行
t1执行
t2执行
t1执行
t2执行
t1执行
...

sleep()

  • sleep是一个静态方法,它接受一个long类型的毫秒值参数,而且是一个本地方法(native修饰),而且会抛出InterruptedException(中断异常)。
  • sleep()这个方法的使用很简单,直接Thread.sleep(毫秒值),休眠指定的毫秒数。使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会执行。但是时间到了之后线程会进入就绪队列,重新去竞争cpu资源。
  • sleep()会释放cpu资源,但是不会释放同步锁(类锁和对象锁)

什么叫释放cpu资源呢?解释如下:

例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了。

总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

yield()

使当前正在执行的线程向另一个线程交出运行权。注意这是一个静态方法。
该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
1、yield()执行后线程直接进入就绪状态。
2、yield()会释放cpu资源,但是不会释放同步锁(类锁和对象锁)

join()

执行后线程进入阻塞状态,例如在线程B中调用线程A的join(),那线程B会进入到阻塞队列,直到A结束或中断线程B。
可以实现一个线程的顺序执行。

wait()

使调用该方法的线程释放共享资源锁,然后从运行状态退出,进入等待队列,直到被再次唤醒

notify()

随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。

notifyAll()

使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM虚拟机的实现。

sleep和wait的区别

  • 当线程执行sleep方法时,不会释放当前的锁(如果当前线程进入了同步锁),也不会让出CPU。sleep(milliseconds)可以用指定时间使它自动唤醒过来,如果时间不到只能调用interrupt方法强行打断。
  • 当线程执行wait方法时,会释放当前的锁,然后让出CPU,进入等待状态。只有当notify/notifyAll被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized代码块的代码或是中途遇到wait() ,再次释放锁。

wait、notify/notifyAll和sleep的区别与联系

  • 前三个方法是Object的本地final方法,sleep方法是Thead类的静态方法。
  • wait使当前线程阻塞,前提是必须先获得锁,所以只能在synchronized锁范围内里使用wait、notify/notifyAll方法,而sleep可以在任何地方使用。
  • sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。
  • notify和wait的顺序不能错,如果A线程先执行notify方法,B线程在执行wait方法,那么B线程是无法被唤醒的。

notify和notifyAll的区别

  • notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
  • notifyAll会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll方法。

锁池和等待池

1.锁池
所有需要竞争同步锁的线程都会放在锁池当中,比如当前对象的锁已经被其中一个线程得到,则其他线程需要在这个锁池进行等待,当前面的线程释放同步锁后锁池中的线程去竞争同步锁,当某个线程得到后会进入就绪队列进行等待cpu资源分配。
2.等待池
当我们调用wait()方法后,线程会放到等待池当中,等待池的线程是不会去竞争同步锁。只有调用了notify()或notifyAll()后等待池的线程才会开始去竞争锁。
notify()是随机从等待池选出一个线程放到锁池,而notifyAll()是将等待池的所有线程放到锁池当中。

yield()方法和sleep()方法有什么区别

https://blog.csdn.net/x541211190/article/details/109559372

  • yield()方法调用后线程处于RUNNABLE状态,所以yield()方法调用后线程只是暂时的将调度权让给别人,但立刻可以回到竞争线程锁的状态
  • sleep()方法调用后线程处于TIME_WAITING状态,sleep()方法调用后线程处于阻塞状态。

sleep()方法和wait()方法的异同点

https://blog.csdn.net/x541211190/article/details/109545132

  • wait()、notify()方法必须写在同步方法中,是为了防止死锁和永久等待,使线程更安全,而sleep()方法不需要有这个限制。
  • wait()方法调用后会释放锁sleep()方法调用后不会释放锁。
  • sleep()方法必须要指定时间参数;wait()方法可以指定时间参数。
  • 两个方法所属类不同,sleep()方法属于Thread类;wait()属于Object类中,放在Object类中是因为Java中每个类都可以是一把锁。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容