java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)

wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

 2)当前线程必须拥有此对象的monitor(即锁),才能调用某个对象的wait()方法能让当前线程阻塞,

(这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁)

 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

(notify()或者notifyAll()方法并不是真正释放锁,必须等到synchronized方法或者语法块执行完才真正释放锁)

 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

例子1(错误使用导致线程阻塞):三个线程,线程3先拥有sum对象的锁,然后通过sum.notify()方法通知等待sum锁的线程去获得锁,但是这个时候线程1,2并没有处于wait()导致的阻塞状态,而是在synchronized方法块处阻塞了,所以,这次notify()根本没有通知到线程1,2。然后线程3正常结束,释放掉sum锁,这个时候,线程1就立刻获得了sum对象的锁(通过synchronized获得),然后调用sum.wait()方法释放掉sum的锁,线程2随后获得了sum对象的线程锁(通过synchronized获得),这个时候线程1,2都处于阻塞状态,但是悲催的是,这之后再也没有线程主动调用sum.notify()或者notifyAll()方法显示唤醒这两个线程,所以程序阻塞

Java代码  

  1. public class CyclicBarrierTest {
  2. public static void main(String[] args) throws Exception {
  3. final Sum sum=new Sum();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void  run() {
  7. try {
  8. synchronized (sum) {
  9. System.out.println("thread3 get lock");
  10. sum.sum();
  11. sum.notifyAll(); //此时唤醒没有作用,没有线程等待
  12. Thread.sleep(2000);
  13. System.out.println("thread3 really release lock");
  14. }
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. new Thread(new Runnable() {
  21. @Override
  22. public void  run() {
  23. try {
  24. synchronized (sum) {
  25. System.out.println("thread1 get lock");
  26. sum.wait();//主动释放掉sum对象锁
  27. System.out.println(sum.total);
  28. System.out.println("thread1 release lock");
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }).start();
  35. new Thread(new Runnable() {
  36. @Override
  37. public void  run() {
  38. try {
  39. synchronized (sum) {
  40. System.out.println("thread2 get lock");
  41. sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)
  42. System.out.println(sum.total);
  43. System.out.println("thread2 release lock");
  44. }
  45. } catch (Exception e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }).start();
  50. }
  51. }
  52. class Sum{
  53. public Integer total=0;
  54. public void  sum() throws Exception{
  55. total=100;
  56. Thread.sleep(5000);
  57. }
  58. }

运行结果:

Java代码  

  1. thread3 get lock
  2. thread3 really release lock
  3. thread2 get lock
  4. thread1 get lock
  5. //程序后面一直阻塞

例子2:还是上面程序,顺序不同,把线程3放到最下面。最后线程1,2都因为没有再次获得线程导致线程阻塞

运行过程:

线程1先运行获得sum对象锁(通过synchronized),但是随后执行了sum.wait()方法,主动释放掉了sum对象锁,然后线程2获得了sum对象锁(通过synchronized),也通过sum.wait()失去sum的对象锁,最后线程3获得了sum对象锁(通过synchronized),主动通过sum.notify()通知了线程1或者2,假设是1,线程1重新通过notify()/notifyAll()的方式获得了锁,然后执行完毕,随后线程释放锁,然后这个时候线程2成功获得锁,执行完毕。

Java代码  

  1. public class CyclicBarrierTest {
  2. public static void main(String[] args) throws Exception {
  3. final Sum sum=new Sum();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void  run() {
  7. try {
  8. synchronized (sum) {
  9. System.out.println("thread1 get lock");
  10. sum.wait();//主动释放sum对象锁,等待唤醒
  11. System.out.println(sum.total);
  12. System.out.println("thread1 release lock");
  13. }
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }).start();
  19. new Thread(new Runnable() {
  20. @Override
  21. public void  run() {
  22. try {
  23. synchronized (sum) {
  24. System.out.println("thread2 get lock");
  25. sum.wait();  //主动释放sum对象锁,等待唤醒
  26. System.out.println(sum.total);
  27. System.out.println("thread2 release lock");
  28. }
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }).start();
  34. new Thread(new Runnable() {
  35. @Override
  36. public void  run() {
  37. try {
  38. synchronized (sum) {
  39. System.out.println("thread3 get lock");
  40. sum.sum();
  41. sum.notifyAll();//唤醒其他等待线程(线程1,2)
  42. Thread.sleep(2000);
  43. System.out.println("thread3 really release lock");
  44. }
  45. } catch (Exception e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }).start();
  50. }
  51. }
  52. class Sum{
  53. public Integer total=0;
  54. public void  sum() throws Exception{
  55. total=100;
  56. Thread.sleep(5000);
  57. }
  58. }

执行结果:

Java代码  

    1. thread1 get lock
    2. thread2 get lock
    3. thread3 get lock
    4. thread3 really release lock
    5. 100
    6. thread2 release lock
    7. 100
    8. thread1 release lock

转自 https://blog.csdn.net/azhegps/article/details/63031562

原文地址:https://www.cnblogs.com/tiancai/p/8855125.html

时间: 2024-08-04 16:29:07

java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)的相关文章

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

Java并发编程系列[未完]: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) 一.线程的状态 Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态). New:新建状态,当线程创建完成时为新

java基础知识回顾之java Thread类学习(九)--wait和notify区别

wait和sleep区别:  相同点:调用wait,sleep方法都可以是线程进入阻塞状态,让出cpu的执行权. 不同点:1.sleep必须指定时间,但是wait方法可以指定时间,也可以不指定时间. 2.wait方法必须在同步中使用,但是sleep不一定在同步中使用. 3.在同步中,调用sleep方法释放CPU执行权,但是不会释放锁,即使让出了CPU执行权,其它线程也无法进入同步锁,不能得到执行.但是wait  方法不仅释放CPU执行权,而且释放同步锁,进入阻塞状态.也就是说其它等待此锁的线程可

【Java并发系列02】Object的wait()、notify()、notifyAll()方法使用

一.前言 对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多. 二.线程安全基本知识 首先应该记住以下基本点,先背下来也无妨: 同一时间一个锁只能被一个线程持有 调用对象的wait()和notify()前必须持有它 三.wait()和notify()理解 3.1 wait()和notify()方法简介 wait()和notify()都是Object的方法,可以认为任意一个Object都是一种资源(或者资源的一个代表),当多个

notify,wait,synchronized实现线程间通知

wait阻塞线程释放锁:notify使wait所在的线程被唤醒在次获得锁,并执行,但要等到notify所在的线程代码全部执行后! 示例代码如下: package com.vhbi.service.impl; import com.sun.org.apache.xerces.internal.xs.datatypes.ObjectList; import java.util.LinkedList; import java.util.List; import java.util.concurrent

【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信.在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回. Object是所有类的超类,它有5个方法组成了等待/通知机制的核心:notify().notifyAll().wait().wait(long

转:【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明

转载请注明出处:http://blog.csdn.net/ns_code/article/details/17225469    在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信.在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回. Object

java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)

一.Condition 类 在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.concurrent.locks.ReentrantLock 锁,JDK也为我们提供了与此功能相应的类java.util.concurrent.locks.Condition.Condition与重入锁是通过lock.newCondition()方法产生一个与当前重入锁绑定的Condtion实例,我们

(转) Java线程同步阻塞, sleep(), suspend(), resume(), yield(), wait(), notify()

为了解决对共享存储区的访问冲突,Java 引入了同步机制.但显然不够,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个. 为解决访问控制问题,Java 引入阻塞机制.阻塞指的是暂停一个Java线程同步的执行以等待某个条件发生(如某资源就绪). sleep():允许指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时 间,指定的时间一过,线程重新进入可执行状态.典型地,sleep() 被用在等待某个资源就绪的情