java线程中join(),yield(),sleep(),wait(),notify()区别详解

https://blog.csdn.net/qxs965266509/article/details/8134334

1 sleep(long millis):Thread类,必须带一个时间参数

  • sleep(long):使调用该方法的线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行

  • sleep(long)是不会释放锁标志的也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据

  • sleep(long)可使优先级低的线程得到执行的机会,当然也可以让同优先级的线程有执行的机会

  • 该方法要捕捉异常

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

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

2 join():Thread类

Thread类中的join()的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行

  • 用途:join()方法使调用该方法的线程在此之前执行完毕,也就是等待 该方法的线程执行完毕后 再往下继续执行
  • 该方法要捕捉异常

join()详情请看:
https://mp.csdn.net/mdeditor/81226972#

3 yield():Thread类,没有参数

  • sleep 方法使当前运行中的线程睡眠一段时间,进入不可以运行状态这段时间的长短是由程序设定的,yield方法使当前线程让出CPU占有权,但让出的时间是不可设定的

  • 只能让同优先级的线程有执行的机会

  • yield()不会释放锁标志

  • 先检测当前是否有相同优先级的线程处于同可运行状态

    • 如有,则把CPU的占有权交给次线程
    • 否则继续运行原来的线程

sleep 方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程此时获取CPU占有权。在一个运行系统中,如果较高优先级的线程没有调用sleep方法,也没有受到I/O阻塞那么较低优先级线程只能等待所有较高优先级的线程运行结束,方可有机会运行

yield()详情请看:
https://blog.csdn.net/csdnlijingran/article/details/82974515

4 wait()、notify()、notifyAll():java.lang.Object

详情请看:
https://blog.csdn.net/csdnlijingran/article/details/88560966

这三个方法都是java.lang.Object的方法。 协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。synchronized关键字用于保护共享数据,阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会访问共享数据呢? 这三个方法的作用:此时就用这三个方法来灵活控制。

线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。

wait()方法使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。

调用notify()方法后,将从对象的等待池中移走一个任意的线程并 放到 锁标志等待池中,只有 锁标志等待池 中线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用

notifyAll()则从对象等待池 中移走 所有等待那个对象的线程 并放到锁标志等待池中。

常用的wait方法有wait()和wait(long timeout)

void wait() :在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前导致当前线程等待

void wait(long timeout):在其他线程调用此对象的notify() 方法 或者 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。

wait()后,线程会释放掉它所占有的“锁标志”,从而使其他 想要锁住共享对象 的线程使用。

wait()和notify()因为会对对象的“锁标志”进行操作,所以他们必需在Synchronized函数或者 synchronized block 中进行调用。如果在non-synchronized 函数或 non-synchronized block 中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常

5 interrupt()

https://blog.csdn.net/hudashi/article/details/6958550

interrupt()只是改变中断状态而已。interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,给受阻塞的线程抛出一个中断信号,这样受阻线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞, 这是调用了该线程的interrupt(),那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态

如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到InterruptedException异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。

  • 线程A在执行sleep,wait,join时,线程B调用线程A的interrupt方法,的确这一个时候A会有InterruptedException 异常抛出来。但这其实是在sleep,wait,join这些方法内部会不断检查中断状态的值,而自己抛出的InterruptedException

  • 如果线程A正在执行一些指定的操作时如赋值,for,while,if,调用方法等,都不会去检查中断状态所以线程A不会抛出 InterruptedException,而会一直执行着自己的操作

注意:当线程A执行到wait(),sleep(),join()时,抛出InterruptedException后,中断状态已经被系统复位了线程A调用Thread.interrupted()返回的是false

  1. sleep() & interrupt()
    线程A正在使用sleep()暂停着: Thread.sleep(100000);
    如果要取消他的等待状态,可以在正在执行的线程里(比如这里是B)调用
    a.interrupt();
    令线程A放弃睡眠操作,这里a是线程A对应到的Thread实例
    当在sleep中时 线程被调用interrupt()时,就马上会放弃暂停的状态.并抛出InterruptedException.丢出异常的,是A线程.
  2. wait() & interrupt()
    线程A调用了wait()进入了等待状态,也可以用interrupt()取消.
    不过这时候要小心锁定的问题.线程在进入等待区,会把锁定解除,当等待中的线程调用interrupt()时,会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的.
  3. join() & interrupt()
    当线程以join()等待其他线程结束时,当它被调用interrupt(),它与sleep()时一样, 会马上跳到catch块里。注意,是对谁调用interrupt()方法,一定是调用被阻塞线程的interrupt方法。
    例如在线程a中调用来线程t.join()。则a会等t执行完后在执行t.join后的代码,当在线程b中调用来 a.interrupt()方法,则会抛出InterruptedException,当然join()也就被取消了

6 run和start()

把需要处理的代码放到run()方法中,start()方法启动线程将自动调用run()方法,这个由java的内存机制规定的。并且run()方法必需是public访问权限,返回值类型为void

7 关键字synchronized

该关键字用于保护共享数据,当然前提条件是要分清哪些数据是共享数据。每个对象都有一个锁标志,当一个线程访问到该对象,被Synchronized修饰的数据将被"上锁",阻止其他线程访问。当前线程访问完这部分数据后,释放锁标志,其他线程就可以访问了

猜你喜欢

转载自blog.csdn.net/csdnlijingran/article/details/88606201