【问题标题】:Need some explanation on my wait and notify code需要对我的等待和通知代码进行一些解释
【发布时间】:2014-01-06 15:44:59
【问题描述】:

请按照下面的代码,

资源.java,

public class Resource {

public void first() {

    Thread t = Thread.currentThread();
    try {
        System.out.println(t.getName() + " : is accessing the method 'first' ");

        synchronized (this) {
            for (int num = 1; num <= 10; num++) {
                System.out.println(t.getName() + " : NUM : " + num);
                Thread.sleep(500);
                if (num == 5) {
                    this.wait();
                }
            }
            this.notify();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public void second() {

    Thread t = Thread.currentThread();
    try {
        System.out.println(t.getName() + " : is accessing the method 'second' ");

        synchronized (this) {
            for (int num = 1; num <= 10; num++) {
                System.out.println(t.getName() + " : X : " + num);
                Thread.sleep(500);
                if (num == 7) {
                    this.notify();
                    this.wait();                       
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}
}

ReqThread.java如下,

public class ReqThread extends Thread{

public ReqThread(String name,Resource res){
    this.setName(name);
    this.res = res;
}

private Resource res;

@Override
public void run(){
    try{
        if("ONE".equals(this.getName())){
            res.first();
        }else{
            res.second();
        }            
    }catch(Exception e){
        e.printStackTrace();
    }
}
}

还有 MainClass.java,

public class MainClass {
public static void main(String [] args){
    Resource res = new Resource();
    ReqThread t1 = new ReqThread("ONE", res);
    ReqThread t2 = new ReqThread("TWO", res);

    t1.start();
    t2.start();
}
}

从上面的代码可以看出,我正在尝试使用等待和通知机制来学习线程通信。

这里线程“ONE”首先启动,然后计数器 5 等待并释放锁,然后线程“TWO”继续(已经处于等待状态),然后其计数器达到 7 通知并等待。

所以我的问题是当线程'TWO'在方法'second'中通知时,是否释放锁?

上面代码的输出是

ONE : is accessing the method 'first' 
ONE : NUM : 1
TWO : is accessing the method 'second' 
ONE : NUM : 2
ONE : NUM : 3
ONE : NUM : 4
ONE : NUM : 5
TWO : X : 1
TWO : X : 2
TWO : X : 3
TWO : X : 4
TWO : X : 5
TWO : X : 6
TWO : X : 7
ONE : NUM : 6
ONE : NUM : 7
ONE : NUM : 8
ONE : NUM : 9
ONE : NUM : 10
TWO : X : 8
TWO : X : 9
TWO : X : 10

现在,如果我在 Resource.java 中的方法 'second' 中更改代码,如下所示

if (num == 7) {
                    this.notify();
                    //this.wait();                       
                }

代码的输出是

ONE : is accessing the method 'first' 
ONE : NUM : 1
TWO : is accessing the method 'second' 
ONE : NUM : 2
ONE : NUM : 3
ONE : NUM : 4
ONE : NUM : 5
TWO : X : 1
TWO : X : 2
TWO : X : 3
TWO : X : 4
TWO : X : 5
TWO : X : 6
TWO : X : 7
TWO : X : 8
TWO : X : 9
TWO : X : 10
ONE : NUM : 6
ONE : NUM : 7
ONE : NUM : 8
ONE : NUM : 9
ONE : NUM : 10

从第二个输出中你可以看到,即使线程“TWO”执行了 notify(),它也不会等待并继续打印数字,

这是因为即使线程 'TWO' 执行了 notify() 但代码仍然处于同步块中,并且它仍然具有尚未释放的锁?

【问题讨论】:

    标签: java multithreading thread-safety


    【解决方案1】:

    答案在 javadoc 中。 Object#notify() 状态

    被唤醒的线程将无法继续,直到当前 线程放弃对该对象的锁定。被唤醒的线程将 以通常的方式与任何其他线程竞争 积极竞争以在此对象上进行同步;

    所以你是对的。调用object.notify() 不会释放object 的监视器。它只是唤醒一个仍然需要竞争才能获得它的线程。

    所以notify() 不会释放监视器,但wait() 会。

    当前线程必须拥有该对象的监视器。 线程释放 此监视器的所有权并等待直到另一个线程通知 在此对象的监视器上等待唤醒的线程要么通过 调用notify 方法或notifyAll 方法。


    如果您对对象同步以及 wait()notify() 的工作方式感到满意,请考虑迁移到为您完成所有这些工作的 java.util.concurrent 包。

    【讨论】:

    • +1 并且在通知线程后对锁的竞争正是我们在多个生产者/消费者实现中存在竞争条件的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2014-10-02
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多