java的notify方法为啥也要同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java的notify方法为啥也要同步相关的知识,希望对你有一定的参考价值。

我知道wait方法同步是为了可以释放调用此方法对象上的锁。notify方法调用可以随即唤醒一个由于调用了该对象wait方法的线程,但是notify为什么也要同步啊?

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。notify()方法和wait()方法的基本思想是给方法或代码块提供一种相互通信的方式,而这些方法或者代码块同步于某个特定对象。代码块可以调用wait()方法来将自身的操作挂起,直到同一个对象上的其他同步方法或同步代码块以某种方式将其改变,并调用notfiy()方法来通知此代码块改变已经完成。一个线程一般会因为它所同步的对象的某个属性没有设置,或者某个条件没有满足而调用wait()方法,这些由另一个线程的动作决定。最简单的情况可能是资源因为正被另一个线程修改而繁忙,还有其他的可能情况。 参考技术A 采纳答案都没说到点子上,基本只是在讲wait和notify的使用...notify方法之所以要同步,是因为wait释放锁后,要想在被唤醒时继续执行wait之后被同步的语句,必须重新获得原本释放掉的锁。notify执行后,会将自己的锁给予随机一个等待中的线程。只有同一锁的notify和wait才能达成停止唤起的操作。这样保证notify不会唤起不具有同一锁的其他线程。你那个对notify方法使用的描述也是基于此。 参考技术B notify也是随机唤醒某个线程,所以不一定能唤醒到调用wait方法的那个,如果要确保能唤醒wait的方法,请用notifyAll

JAVA同步锁机制 wait() notify() notifyAll()

wait() notify() notifyAll() 这3个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块中使用。

  wait() 必须在synchronized函数或者代码块里面,wait()会让已经获得synchronized函数或者代码块控制权的Thread暂时休息,并且丧失控制权,这个时候,由于该现象丧失控制权并且进入等待,其他线程就能取得控制权,并且在适当情况下调用notifyAll() 来唤醒wait()的线程。需要注意的是,被唤醒的线程由于已经丧失控制权,其他的线程可以乘虚而入,所以wait()的使用,必须在2个以上的线程,而且必须在不同的条件下唤醒wait()中的线程。

  notifyAll()并不是让当前线程马上让出控制权,而只是让其他wait()当中的线程唤醒而已,所以尽管我唤醒你,可你必须还是要等我用完仓库才能进来。

    举例说明:生产者和消费者共享的同步机制。

    ProductList 是一个产品仓库,当仓库满的时候,生产者线程需要wait(),从而放弃对产品仓库的控制,这个时候消费者线程就可以进来且取得仓库的控制权,一旦消费者消费了产品,仓库就不再是满,这时候消费者线程就有notifyAll() 生产者线程让等待的生产者线程唤醒,但是生产者不会马上进行生产,需要等消费者线程结束操作,才能重新获得仓库的控制权,再进行生产。

 

//产品类
public class Product {
int id;
private String producedBy = "N/A";
private String consumedBy = "N/A";

//指定生产者名字
Product(String producedBy){
this.producedBy = producedBy;
}

//指定消费者名字
public void consume(String consumedBy){
this.consumedBy = consumedBy;
}

public String toString(){
return "产品,生产者 = "+producedBy +",消费者 = "+consumedBy;
}
public String getProducedBy(){
return producedBy;
}
public void setProducedBy(String producedBy) {
this.producedBy = producedBy;
}

public String getConsumedBy(){
return consumedBy;
}
public void setConsumedBy(String consumedBy) {
this.consumedBy = consumedBy;
}
}



//仓库类
public class ProductList {
int index = 0;
Product[] productlist = new Product[6];

//生产者存放产品
public synchronized void push(Product product){
//仓库满了
while (index == productlist.length){
try {
System.out.println(" "+product.getProducedBy() + "is waiting.");
wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
//notifyAll()之后,还是会继续执行直到完成
productlist[index] = product;
index++;
System.out.println(index+" " + product.getProducedBy()+"生产了:"+product);
notifyAll();
System.out.println(" "+product.getProducedBy()+"send a notifyAll().");
}


//消费者 取出产品
public synchronized Product pop(String consumeName){
while (index ==0){//仓库空了
try {
System.out.println(" "+consumeName+"is waiting.");
wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}

//一样会继续执行到完成
index--;
Product product = productlist[index];
product.consume(consumeName);
System.out.println(index+""+product.getConsumedBy()+" 消费了:"+product);
notifyAll();
return product;
}
}

//生产者类
public class Producer implements Runnable {
String name;
ProductList ps = null;
Producer(ProductList ps,String name){
this.ps = ps;
this.name = name;
}

public void run(){
while (true){
Product product = new Product(name);
ps.push(product);
try {
Thread.sleep((int)(Math.random() * 200));
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}

//消费者类
public class Consumer implements  Runnable{
String name;
ProductList ps = null;

Consumer(ProductList ps ,String name){
this.ps = ps;
this.name = name;
}

@Override
public void run() {
while (true){
ps.pop(name);
try {
Thread.sleep(((int)Math.random() * 1000));
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}


//测试类

public class Test {
public static void main(String[] args) {
ProductList ps = new ProductList();
Producer px = new Producer(ps,"生产者X");
Producer py = new Producer(ps,"生产者Y");

Consumer ca = new Consumer(ps,"消费者A");
Consumer cb = new Consumer(ps,"消费者B");
Consumer cc = new Consumer(ps,"消费者C");

new Thread(px).start();
new Thread(py).start();
new Thread(ca).start();
new Thread(cb).start();
new Thread(cc).start();
}

}
 



 



















































































































































以上是关于java的notify方法为啥也要同步的主要内容,如果未能解决你的问题,请参考以下文章

为啥wait,notify和notifyAll必须在同步块或同步方法中调

Java 线程中调用wait为啥一定要在同步代码块中?

为啥方法 wait() 在没有 notify() 的情况下工作?

从Guarded Block来看Java中的wait和notify方法

java中wait,notify,notifyAll,sleep方法的作用和区别

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