利用Object的wait、notify来实现线程同步原理,Thread t1 = new Thread(new Runnable() {

  • Post author:
  • Post category:其他




认识Object.wait()方法:



导致当前线程等待,直到该对象的notify或notifyAll被执行。换句话说,这个方法行为效果完全与简单调用wait(0)一样。当前线程必须拥有对象监视器。线程释放对象监视器的所有权,等待直到另一个线程通过调用notify或notifyAll来通知等待对象监视器的线程们并唤醒。然后,当前线程等待重新获取对象监视器并继续执行。因为在一个参数的版本中,中断与伪唤醒是可能的,这个方法应该通常在一个循环中使用:

synchronized (obj) {


while (<condition does not hold>)

obj.wait();

… // Perform action appropriate to condition

}

该方法必须同步执行的,否则会抛出IllegalMonitorStateException。


认识Object.wait(long)方法:


基本功能与Object.wait()相同,只是在指定时间间隔后,当前线程自动唤醒,并与其它线程竞争对象监视器,在获取对象监视器后,当前线程继续向前执行。


认识Object.notify方法:


唤醒等待这个对象的监视器的单一线程。如果有很多线程在等待该对象监视器,则选择其中的一个来唤醒。这歌选择是任意的,与具体的实现相关。一个线程调用wait方法后就等待对象监视器。被唤醒的线程将在当前线程放弃对象锁后才能继续执行,它在竞争该对象锁方面没有任何可靠的特权或劣势。调用这个方法必须占有对象监视器。线程通过3中途径可以占有对象监视器:

(1)执行对象的同步方法;

(2)执行锁定对象的同步语句块;

(3)执行类对象的静态同步方法。

在某一时刻,只有一个线程占有对象监视器。该方法必须同步执行的,否则会抛出IllegalMonitorStateException。

通过下面的一个例子来说明:

Java代码

收藏代码



  1. final


    Object synObj =


    new


    Object();


  2. Thread t1 =

    new


    Thread(


    new


    Runnable() {



  3. @Override





  4. public




    void


    run() {



  5. synchronized


    (synObj) {


  6. System.out.println(

    “T1获取synObj的对象监视器,开始执行同步块”


    );



  7. try


    {


  8. TimeUnit.MINUTES.sleep(

    1


    );


  9. System.out.println(

    “T1在 wait()时挂起了”


    );


  10. synObj.wait();

  11. System.out.println(

    “T1被T2唤醒后并重新获得synObj的对象监视器,继续执行”


    );


  12. }

    catch


    (InterruptedException e) {


  13. e.printStackTrace();

  14. }

  15. System.out.println(

    “T1获取synObj的对象监视器,结束同步块”


    );


  16. }

  17. };

  18. });

  19. t1.start();



  20. Thread t2 =

    new


    Thread(


    new


    Runnable() {



  21. @Override





  22. public




    void


    run() {


  23. System.out.println(

    “T2启动,但是因为T1占用了synObj的对象监视器,则等待T1执行synObj.wait来释放它”


    );



  24. synchronized


    (synObj) {



  25. try


    {


  26. System.out.println(

    “在T1执行synObj.wait后,T2获取synObj的对象监视器,进入同步块”


    );


  27. synObj.notify();

  28. System.out.println(

    “T2执行synObj.notify(),T1被唤醒,但T2还在同步块中,没有释放synObj的对象监视器,T1等待synObj的对象监视器”


    );


  29. TimeUnit.MINUTES.sleep(

    1


    );


  30. System.out.println(

    “T2结束同步块,释放synObj的对象监视器,T1获取到synObj的对象监视器,并执行wait后面的操作”


    );


  31. }

    catch


    (InterruptedException e) {


  32. e.printStackTrace();

  33. }

  34. }

  35. };

  36. });

  37. t2.start();

输出:



T1获取synObj的对象监视器,开始执行同步块

T2启动,但是因为T1占用了synObj的对象监视器,则等待T1执行synObj.wait来释放它

T1在 wait()时挂起了

在T1执行synObj.wait后,T2获取synObj的对象监视器,进入同步块

T2执行synObj.notify(),T1被唤醒,但T2还在同步块中,没有释放synObj的对象监视器,T1等待synObj的对象监视器

T2结束同步块,释放synObj的对象监视器,T1获取到synObj的对象监视器,并执行wait后面的操作

T1被T2唤醒后并重新获得synObj的对象监视器,继续执行

T1获取synObj的对象监视器,结束同步块



注意,对象监视器就是对象锁,在object.notify()后,被唤醒的线程还不能立即执行,必须等待到对象锁。



版权声明:本文为Baple原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。