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

转自:http://turbosky.iteye.com/blog/2314144 该博主针对wait()和notify()方法解释得不错,故转之。

   wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行, 只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还 在别人手里,别人还没释放。如果notify/notifyAll方法后面的代码还有很多,需要这些代码执行完后才会释放锁),调用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.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.         new Thread(new Runnable() {  
  7.             @Override  
  8.             public void  run() {  
  9.                 try {  
  10.                     synchronized (sum) {  
  11.                         System.out.println(”thread3 get lock”);  
  12.                         sum.sum();  
  13.                         sum.notifyAll(); //此时唤醒没有作用,没有线程等待  
  14.                         Thread.sleep(2000);  
  15.                         System.out.println(”thread3 really release lock”);  
  16.                     }  
  17.                       
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println(”thread1 get lock”);  
  30.                         sum.wait();//主动释放掉sum对象锁  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println(”thread1 release lock”);  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println(”thread2 get lock”);  
  46.                         sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)  
  47.                         System.out.println(sum.total);  
  48.                         System.out.println(”thread2 release lock”);  
  49.                     }  
  50.                 } catch (Exception e) {  
  51.                     e.printStackTrace();  
  52.                 }  
  53.             }  
  54.         }).start();  
  55.     }  
  56.             
  57. }  
  58.   
  59. class Sum{  
  60.     public Integer total=0;  
  61.       
  62.     public void  sum() throws Exception{  
  63.         total=100;  
  64.         Thread.sleep(5000);  
  65.     }  
  66.       
  67. }  
public class CyclicBarrierTest {

    public static void main(String[] args) throws Exception {
        final Sum sum=new Sum();

        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread3 get lock");
                        sum.sum();
                        sum.notifyAll(); //此时唤醒没有作用,没有线程等待
                        Thread.sleep(2000);
                        System.out.println("thread3 really release lock");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread1 get lock");
                        sum.wait();//主动释放掉sum对象锁
                        System.out.println(sum.total);
                        System.out.println("thread1 release lock");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread2 get lock");
                        sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)
                        System.out.println(sum.total);
                        System.out.println("thread2 release lock");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

}

class Sum{
    public Integer total=0;

    public void  sum() throws Exception{
        total=100;
        Thread.sleep(5000);
    }

}
 

 

    运行结果:

 

Java代码   收藏代码
  1. thread3 get lock  
  2. thread3 really release lock  
  3. thread2 get lock  
  4. thread1 get lock  
  5. //程序后面一直阻塞  
thread3 get lock
thread3 really release lock
thread2 get lock
thread1 get lock
//程序后面一直阻塞
 例子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.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.       
  7.           
  8.         new Thread(new Runnable() {  
  9.             @Override  
  10.             public void  run() {  
  11.                 try {  
  12.                     synchronized (sum) {  
  13.                         System.out.println(”thread1 get lock”);  
  14.                         sum.wait();//主动释放sum对象锁,等待唤醒  
  15.                         System.out.println(sum.total);  
  16.                         System.out.println(”thread1 release lock”);  
  17.                     }  
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println(”thread2 get lock”);  
  30.                         sum.wait();  //主动释放sum对象锁,等待唤醒  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println(”thread2 release lock”);  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println(”thread3 get lock”);  
  46.                         sum.sum();  
  47.                         sum.notifyAll();//唤醒其他等待线程(线程1,2)  
  48.                         Thread.sleep(2000);  
  49.                         System.out.println(”thread3 really release lock”);  
  50.                     }  
  51.                       
  52.                 } catch (Exception e) {  
  53.                     e.printStackTrace();  
  54.                 }  
  55.             }  
  56.         }).start();  
  57.           
  58.           
  59.     }  
  60.             
  61. }  
  62.   
  63. class Sum{  
  64.     public Integer total=0;  
  65.       
  66.     public void  sum() throws Exception{  
  67.         total=100;  
  68.         Thread.sleep(5000);  
  69.     }  
  70.       
  71. }  
public class CyclicBarrierTest {

    public static void main(String[] args) throws Exception {
        final Sum sum=new Sum();



        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread1 get lock");
                        sum.wait();//主动释放sum对象锁,等待唤醒
                        System.out.println(sum.total);
                        System.out.println("thread1 release lock");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread2 get lock");
                        sum.wait();  //主动释放sum对象锁,等待唤醒
                        System.out.println(sum.total);
                        System.out.println("thread2 release lock");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void  run() {
                try {
                    synchronized (sum) {
                        System.out.println("thread3 get lock");
                        sum.sum();
                        sum.notifyAll();//唤醒其他等待线程(线程1,2)
                        Thread.sleep(2000);
                        System.out.println("thread3 really release lock");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }

}

class Sum{
    public Integer total=0;

    public void  sum() throws Exception{
        total=100;
        Thread.sleep(5000);
    }

}

 

执行结果:

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  
thread1 get lock
thread2 get lock
thread3 get lock
thread3 really release lock
100
thread2 release lock
100
thread1 release lock

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java中的waitnotify是多线程编程中的两个重要方法,用于线程之间的协作和通信。 wait方法可以使当前线程进入等待状态,直到其他线程调用notifynotifyAll方法唤醒它。在调用wait方法时,当前线程释放它所持有的,以便其他线程可以访问共享资源。 notify方法用于唤醒一个处于等待状态的线程,如果有多个线程在等待,则只唤醒其中一个线程notifyAll方法则唤醒所有处于等待状态的线程waitnotify方法必须在同步块中使用,即在使用这两个方法的对象上获取。否则抛出IllegalMonitorStateException异常。 使用waitnotify方法可以实现线程之间的协作和通信,例如生产者消费者模型。在生产者消费者模型中,生产者线程生产数据并将其放入共享队列中,消费者线程从队列中取出数据并进行消费。当队列为空时,消费者线程需要等待生产者线程生产数据,此时可以使用wait方法使消费者线程进入等待状态。当生产者线程生产数据并将其放入队列中时,可以使用notify方法唤醒处于等待状态的消费者线程。 ### 回答2: Java线程中的 waitnotify 是两个非常重要的方法,它们可以帮助线程之间达成协作,实现复杂的操作。wait 方法用于让当前线程进入等待状态,直到其他线程通过 notify 方法通知它继续执行。notify 方法则用于唤醒一个等待状态的线程,使其继续执行。 wait 方法 wait 方法用于让当前线程进入等待状态,直到其他线程通过 notifynotifyAll 方法唤醒它。wait 方法需要在 synchronized 代码块中使用,否则抛出 IllegalMonitorStateException 异常。在进入等待状态之后,线程释放,并且进入一个等待池中,等待其他线程调用 notifynotifyAll 方法唤醒它。 notify 方法 notify 方法用于唤醒一个等待状态的线程,使其继续执行。notify 方法同样需要在 synchronized 代码块中使用,否则同样抛出 IllegalMonitorStateException 异常。当一个线程调用 notify 方法时,等待池中的线程被唤醒,但是它们不能马上继续执行,必须等待当前线程释放。如果有多个线程在等待池中,notify 方法只唤醒其中一个线程,具体唤醒哪个线程是随机的。 notifyAll 方法 notifyAll 方法与 notify 方法类似,但是它唤醒所有等待池中的线程notifyAll 方法同样需要在 synchronized 代码块中使用。 使用 waitnotify 实现线程协作 waitnotify 方法可以用来实现线程之间的协作,例如生产者和消费者问题。假设我们有一个共享的队列,生产者向队列中添加数据,消费者从队列中取出数据。如果队列已经满了,生产者就需要等待消费者取走数据,如果队列是空的,消费者就需要等待生产者加入新数据。 在这个问题中,我们可以使用 waitnotify 方法来实现线程之间的协作,代码如下: ``` public class Queue { private final List<Integer> items = new LinkedList<>(); private static final int MAX_SIZE = 10; public synchronized void produce(int item) throws InterruptedException { while (items.size() == MAX_SIZE) { wait(); } items.add(item); notify(); } public synchronized int consume() throws InterruptedException { while (items.isEmpty()) { wait(); } int item = items.remove(0); notify(); return item; } } public class Producer implements Runnable { private final Queue queue; public Producer(Queue queue) { this.queue = queue; } public void run() { for (int i = 0; i < 20; i++) { try { queue.produce(i); System.out.println("Produced: " + i); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } public class Consumer implements Runnable { private final Queue queue; public Consumer(Queue queue) { this.queue = queue; } public void run() { for (int i = 0; i < 20; i++) { try { int item = queue.consume(); System.out.println("Consumed: " + item); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } public class Main { public static void main(String[] args) throws InterruptedException { Queue queue = new Queue(); Thread producer = new Thread(new Producer(queue)); Thread consumer = new Thread(new Consumer(queue)); producer.start(); consumer.start(); producer.join(); consumer.join(); } } ``` 在这个示例代码中,我们创建了一个 Queue 类,它有两个方法 produce 和 consume 用于生产和消费数据。在 produce 方法中,我们使用 while 循环来等待队列不满,如果队列已经满了,就调用 wait 方法进入等待状态。在 consume 方法中,我们使用 while 循环来等待队列不空,如果队列是空的,就调用 wait 方法进入等待状态。在生产新数据或者消费数据之后,我们都调用 notify 方法来唤醒等待池中的线程。 最后,我们可以使用 Producer 和 Consumer 类来生产和消费数据,它们分别运行在不同的线程中。在运行这个程序时,生产者将不断生产数据,消费者将不断消费数据,一直到数据生产完毕为止。在这个过程中,生产者和消费者之间通过 waitnotify 方法实现了线程之间的协作。 ### 回答3: Java是一种支持多线程的编程语言,在多线程编程过程中,一个线程可能需要等待另一个线程的某个条件满足后才能继续执行。Java提供了waitnotify来实现线程之间的协作。 wait:使当前线程进入等待状态,释放对象的,直到其他线程调用notifynotifyAll方法唤醒它。wait方法必须在持有对象的情况下调用,否则抛出IllegalMonitorStateException异常。 notify:唤醒一个处于等待状态的线程,如果有多个线程等待,则只唤醒其中一个,具体唤醒哪个线程无法预测。 notifyAll:唤醒所有处于等待状态的线程waitnotify必须在同步代码块中调用,并且针对同一个对象。waitnotify的调用顺序也非常重要,如果先调用了notify而没有等待线程导致唤醒失效。 在多线程编程中,waitnotify常常用于生产者和消费者模式中的线程之间的通信,生产者线程在生产完毕后调用notify方法唤醒消费者线程来消费数据,消费者线程在消费完毕后调用wait方法等待下一个生产者线程的唤醒。 waitnotify的使用需要谨慎,如果使用不当,导致死线程饥饿等问题。同时,在Java SE 5之后,Java提供了更加高级的线程库,如ReentrantLock、Condition等,可以更加方便和安全地实现线程之间的协作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值