Java notify/notifyall是否释放所持有的锁

Java notify/notifyall是否释放所持有的锁,java,multithreading,locking,Java,Multithreading,Locking,我对等待和通知有点困惑 我知道每个java对象都有一个锁。我知道等待将释放其他线程的锁。notify/notifyall怎么样?notify/notifyAll是否释放它为其他线程持有的锁? wait()告诉调用线程放弃监视器并进入睡眠状态,直到其他线程出现 线程进入同一监视器并调用notify() notify()唤醒在同一对象上调用wait()的线程 notifyAll()唤醒在同一对象上调用wait()的所有线程。这个 最高优先级的线程将首先运行 否--通知/通知所有人不要像等待那样释放锁

我对等待和通知有点困惑

我知道每个java对象都有一个锁。我知道等待将释放其他线程的锁。notify/notifyall怎么样?notify/notifyAll是否释放它为其他线程持有的锁?

  • wait()告诉调用线程放弃监视器并进入睡眠状态,直到其他线程出现 线程进入同一监视器并调用notify()

  • notify()唤醒在同一对象上调用wait()的线程

  • notifyAll()唤醒在同一对象上调用wait()的所有线程。这个 最高优先级的线程将首先运行

否--
通知
/
通知所有人
不要像
等待
那样释放锁。在调用
notify
的代码释放其锁之前,唤醒的线程无法运行

这就是Javadoc所说的:

线程释放此监视器的所有权并等待,直到另一个线程通过调用notify方法或notifyAll方法通知等待此对象监视器的线程唤醒。然后线程等待,直到它可以重新获得监视器的所有权并恢复执行


我必须不同意那些说
notifyAll()
释放对象上的锁的人,在该对象上等待线程和通知线程正在同步

例如:

消费者
类包含一个块:

synchronized(sharedObject){
if(sharedObject.isReadyToConsume() == false){
     sharedObject.wait();
}else {
    sharedObject.doTheThing();
    System.out.println("consumer consuming...");
 }
}

场景:Consumer类获取sharedObject对象的锁,以独占方式进入(它位于同步块内),并看到sharedObject尚未准备就绪(无需消费:),它调用
sharedObject上的
wait()
方法。这样,当另一个线程(可能是生产者)调用
sharedObject.notify()时,它会释放锁(在那里停止执行!),并等待通知继续执行
sharedObject.notifyAll()。收到通知后,它将从等待()行继续

sharedObject跟踪请求通知它的线程。当一些线程调用sharedObject.notifyAll()方法时,sharedObject将通知等待的线程唤醒。。。 现在,棘手的部分是线程在到达同步(sharedObject){}块的末尾时自然地释放对象的锁。问题是如果调用该块中的notifyAll(),会发生什么notifyAll()唤醒等待的线程,但锁仍然属于刚刚调用了notifyAll()的线程。

请看生产者代码段:

synchronized(sharedObject){
//We are exlusively working with sharedObject and noone can enter it
[... changing the object ...]
sharedObject.notifyAll();     //notifying the waiting threads to wake up

Thread.sleep(1000);           //Telling the current thread to go to sleep. It's holding the LOCK
System.out.println("awake...");
}

如果notifyAll()将释放锁,那么在使用者类已经开始使用sharedObject之后,“唤醒…”将被打印出来。事实并非如此。。。输出显示生产者退出其同步块后消费者正在消费sharedObject

  • wait()-释放锁并在收到通知时继续下一行
  • notify(),notifyAll()-不要释放锁。它们只是使等待的线程再次可运行(而不是空闲)。他们将有权在 当前线程到达其同步块和线程的末尾 scheduleder告诉他们锁已被释放。争夺 锁又开了

为了澄清我的理解,并为所有人提供一个释放锁的示例,我在调用notify()/NotifyAll()后向以下代码添加了print语句:

由于输出getSharedChar能够在
setSharedChar之前出现,因此调用notifyAll()可以立即释放锁,或者不需要重新输入同步的getSharedChar()函数。锁可能仍然存在,但是如果您可以在没有锁的情况下重新输入函数,有什么区别?
我可以看到类似的输出将notifyAll()替换为notifyAll()。这是在64位Windows 7系统上的Java 1.7.015上完成的。

假设一群读者想要读取某些资源的更新值,这些值将由Writer更新。然后,读者如何知道资源字段已由作者更新

因此,为了在公共资源上的读写器之间同步此类案例,使用了对象类的三种最终方法

  • 等等
  • 通知()
  • notifyAll()
等待:读卡器希望读取资源的更新值,他们向资源对象注册,即当更新发生在同一对象上时,当写入器通知它时,读卡器将尝试获取资源锁并读取更新的资源。 -仅当读卡器具有Lock对象时才调用Wait,在本例中,它是资源。 -一旦调用wait方法,读取器就会释放锁对象。 -现在,只有同一注册对象(资源)的读卡器才会收到通知信号。 -若读取器调用wait-on对象,这与用于发送通知的对象编写器不同,读取器将永远不会得到通知信号。 -一旦通知了读卡器,现在读卡器将尝试为锁读取内容(其中一个获得了锁)并读取资源的更新值。类似地,其他读取器也可以获得锁并读取更新的值。 -一旦读卡器读取了更新的值,执行业务逻辑并从同步块中出来,读卡器将释放锁,以便其他读卡器可以获取它

通知:写入程序进入同步块,在获取锁执行其业务逻辑后,更新资源对象,一旦更新资源对象,它将通知等待的线程(Reade
class ThreadDemo {
    public static void main(String[] args) {
        Shared s = new Shared();
        new Producer(s).start();
        new Consumer(s).start();
    }
}

class Shared {
    private char c = '\u0000';
    private boolean writeable = true;

    synchronized void setSharedChar(char c) {
        while (!writeable)
            try {
                wait();
            } catch (InterruptedException e) {
            }

        this.c = c;
        writeable = false;
        notifyAll();
        System.out.println("setSharedChar notify() called - still in synchronized block.");
    }

    synchronized char getSharedChar() {
        while (writeable)
            try {
                wait();
            } catch (InterruptedException e) {
            }

        writeable = true;
        notifyAll();
        System.out.println("getSharedChar notify() called - still in synchronized block.");

        return c;
    }
}

class Producer extends Thread {
    private Shared s;

    Producer(Shared s) {
        this.s = s;
    }

    public void run() {
        System.out.println("Starting producer thread.");
        for (char ch = 'A'; ch <= 'Z'; ch++) {
            System.out.println("Producer thread getting ready to create a char.");
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
            }

            s.setSharedChar(ch);
            System.out.println(ch + " produced by producer.");
        }
    }
}

class Consumer extends Thread {
    private Shared s;

    Consumer(Shared s) {
        this.s = s;
    }

    public void run() {
        System.out.println("Starting consumer thread.");
        char ch;

        do {
            System.out.println("Consumer thread getting ready to read a char.");
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
            }

            ch = s.getSharedChar();
            System.out.println(ch + " consumed by consumer.");
        } while (ch != 'Z');
    }
}
...
F produced by producer.
Producer thread getting ready to create a char.
getSharedChar notify() called - still in synchronized block.
F consumed by consumer.
Consumer thread getting ready to read a char.
setSharedChar notify() called - still in synchronized block.
G produced by producer.
Producer thread getting ready to create a char.
getSharedChar notify() called - still in synchronized block.
setSharedChar notify() called - still in synchronized block.
G consumed by consumer.
   public class Resource {
      private String mesg;

          public void setMesg(String mesg){
         this.mesg =mesg;
      }
      public String getMesg(){
         return this.mesg;
      }
    }
public class WaitThreadTask implements Runnable {

    private Resource resource;

    public WaitThreadTask(Resource resource){
        this.resource = resource;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized(resource){
            System.out.println("Before Reading Updated Value By : " +Thread.currentThread().getName() );
            //We need to Take care to get the updated value, so waiting for writer thread to update value.
            try {
                //Release resource Lock & wait till any notification from Writer.
                resource.wait();
                System.out.println("Waiting is Over For : "+ Thread.currentThread().getName());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //Read Updated Value
            System.out.println("Updated Value of Resource Mesg :" + resource.getMesg() + " Read By :" +Thread.currentThread().getName());
        }
    }
}
public class WriterThreadTask implements Runnable{

    private Resource resource;

    public WriterThreadTask(Resource resource){
        this.resource = resource;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized(resource){
            System.out.println("Before Updating Resource By : " + Thread.currentThread().getName());
            //Updating resource Object Message
            resource.setMesg("Hi How are You !!!");
            resource.notify();
            //resource.notifyAll();
            //Once Writer Comes Out from Synch Block, Readers will Content to read the values.
            System.out.println("Task Done By Writer Thread.");
        }
    }
}
public class ThreadDemo {

    public static void main(String args[]){

        //Create Single Resource Object, which can act as Lock on Writer and Readers.

        Resource lock = new Resource();

        //Three Readers and One Writer runnable Tasks.
        Runnable taskR1 = new WaitThreadTask(lock);
        Runnable taskR2 = new WaitThreadTask(lock);
        Runnable taskR3 = new WaitThreadTask(lock);
        Runnable taskW1 = new WriterThreadTask(lock);

        Thread t1 = new Thread(taskR1, "Reader1");
        Thread t2 = new Thread(taskR2, "Reader2");
        Thread t3 = new Thread(taskR3, "Reader3");
        Thread t4 = new Thread(taskW1, "Writer1");

        t1.start();
        t2.start();
        t3.start();

        /*try{
            Thread.sleep(5000);
        } catch(InterruptedException e){
            e.printStackTrace();
        }*/

        t4.start();
    }

}
public class ProducerConsumerInJava {
    public static void main(String args[]) {
      System.out.println("How to use wait and notify method in Java"); 
      System.out.println("Solving Producer Consumper Problem"); 
      Queue<Integer> buffer = new LinkedList<>(); 
      int maxSize = 10; 
      Thread producer = new Producer(buffer, maxSize, "PRODUCER"); 
      Thread consumer = new Consumer(buffer, maxSize, "CONSUMER"); 
      producer.start(); 
      consumer.start(); 
    }
}

class Producer extends Thread {
   private Queue<Integer> queue; 
   private int maxSize; 
   public Producer(Queue<Integer> queue, int maxSize, String name){ 
            super(name); this.queue = queue; this.maxSize = maxSize; 
   }

   public void run() { 
     while (true) { 
              synchronized (queue) { 
                    while (queue.size() == maxSize) { 
                          try { 
                                System.out .println("Queue is full, " +                         
                         "Producer thread waiting for " + "consumer to take 
                          something from queue"); 
                          queue.wait(); 
                    } catch (Exception ex) { 
                        ex.printStackTrace(); 
                        } 
                }
      Random random = new Random(); 
      int i = random.nextInt(); 
      System.out.println("Producing value : " + i); 
      queue.add(i); 
      queue.notifyAll(); 
     } 
    } 
  } 
  }

 class Consumer extends Thread {
   private Queue<Integer> queue; 
   private int maxSize; 
   public Consumer(Queue<Integer> queue, int maxSize, String name){ 
            super(name); this.queue = queue; this.maxSize = maxSize; 
   }

   public void run() { 
     while (true) { 
              synchronized (queue) { 
                    while (queue.isEmpty()) { 
                          try { 
                                System.out .println("Queue is empty," +                         
                         "Consumer thread is waiting" +
                          " for producer thread to put something in queue");
                          queue.wait(); 
                    } catch (Exception ex) { 
                        ex.printStackTrace();
                      }
                  } 
       System.out.println("Consuming value : " + queue.remove()); 
       queue.notifyAll(); 
      } 
    } 
  } 
  }
How to use wait and notify 
method in Java Solving Producer Consumper Problem 
Queue is empty,Consumer thread is waiting for producer thread to put 
something in queue 

Producing value : -1692411980 
Producing value : 285310787 
Producing value : -1045894970 
Producing value : 2140997307 
Producing value : 1379699468 
Producing value : 912077154 
Producing value : -1635438928 
Producing value : -500696499 
Producing value : -1985700664 
Producing value : 961945684 
Queue is full, Producer thread waiting for consumer to take something from 
queue Consuming value : -1692411980 
Consuming value : 285310787 
Consuming value : -1045894970 
 Consuming value : 2140997307 
Consuming value : 1379699468 
Consuming value : 912077154 
Consuming value : -1635438928 
Consuming value : -500696499 
Consuming value : -1985700664 
Consuming value : 961945684 
Queue is empty,Consumer thread is waiting for producer thread to put 
something  in queue 

Producing value : 118213849