繁体   English   中英

Java:wait()和notify()混淆

[英]Java: wait() and notify() confusion

我正在尝试实现一个只能访问一个线程的条件:假设它是一瓶水-我只希望一个人(线程)能够有一个时间。 一切似乎都工作顺利,但我无法显示打印内容–调用wait()之前的内容;

public synchronized void getBotttle  {
    while(myCondition) {
      try {
        System.out.println("Printing that is never done?!");
        wait();
      }
      catch (InterruptedException e) {}
    }

    System.out.println("Printing that works");
    myCondition = true;
    notifyAll(); //or notify(), tried both

    try {
      Thread.sleep(time); // 
    }
    catch (InterruptedException e) {}
    System.out.println("Printing again");
    methodToMakeConditionFalse();
   // notifyAll(); even if I put it here its still the same
}

该方法由线程调用,并且按预期方式工作-只有1个线程带有“瓶”,但没有打印。 有任何想法吗?

有效的答案很简单,你的签名getBotttle()方法的关键字synchronized ,这意味着永远永远远两个不同的线程会同时访问此代码。 因此,使用while(myCondition) { ... }整个块是徒劳的。

其次,建议您研究java.util.concurrent.*包。

UPD。 似乎有必要澄清wait / notifyAll的通常用例是:

public class WaitNotify {

    public static void main(String[] args) throws InterruptedException {
        new WaitNotify().go();
    }

    private void go() throws InterruptedException {
        ResourceProvider provider = new ResourceProvider();
        Consumer c1 = new Consumer("consumer1", provider);
        Consumer c2 = new Consumer("consumer2", provider);
        Consumer c3 = new Consumer("consumer3", provider);
        Consumer[] consumers = new Consumer[] { c1, c2, c3 };

        for (int i = 0; i < consumers.length; i++) {
            provider.grant(consumers[i]);
        }
    }

    public static class ResourceProvider {
        private Resource resource = new Resource();

        public synchronized void grant(Consumer consumer) throws InterruptedException {
            while (resource == null) {
                wait();
            }
            consumer.useResource(resource);
            resource = null;
        }

        public synchronized void putBack(Resource resource) {
            this.resource = resource;
            notifyAll();
        }
    }

    public static class Resource {
        public void doSomething(String consumer) {
            System.out.println("I'm working! " + consumer);
            try {
                Thread.sleep(3L * 1000L);
            } catch (InterruptedException e) { }
        }
    }

    public static class Consumer implements Runnable {
        private String consumer;
        private Resource resource;
        private ResourceProvider provider;

        public Consumer(String consumer, ResourceProvider provider) {
            this.consumer = consumer;
            this.provider = provider;
        }

        public void useResource(Resource r) {
            this.resource = r;
            new Thread(this).start();
        }

        @Override
        public void run() {
            resource.doSomething(consumer);
            provider.putBack(resource);
        }
    }
}

您没有完整的示例,这很难说出您在做什么。 我的猜测是您的条件标记设置不正确。 这是一个有效的完整示例,它确保一次只有一个线程可以访问资源。

public class StuffExample {

    public static void main(String[] args) throws Exception {

        Worker worker = new Worker(new StuffHolder());
        Thread t1 = new Thread(worker); 
        Thread t2 = new Thread(worker); 

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

        Thread.sleep(10000L);
        t1.interrupt();
        t2.interrupt();
    }
}

class Worker implements Runnable {
    private StuffHolder holder;

    public Worker(StuffHolder holder) {
        this.holder = holder;
    }

    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                holder.useStuff();
                Thread.sleep(1000L);
            }
        }
        catch (InterruptedException e) {
        }
    }
}

class StuffHolder {

    private boolean inUse = false;
    private int count = 0;
    public synchronized void useStuff() throws InterruptedException {
        while (inUse) {
            wait();
        }
        inUse = true;
        System.out.println("doing whatever with stuff now, count=" 
            + count + ", thread=" + Thread.currentThread().getName());
        count += 1;
        inUse = false;
        notifyAll();
    }   
}

输出是:

doing whatever with stuff now, count=0, threadid=Thread-0
doing whatever with stuff now, count=1, threadid=Thread-1
doing whatever with stuff now, count=2, threadid=Thread-0
doing whatever with stuff now, count=3, threadid=Thread-1
doing whatever with stuff now, count=4, threadid=Thread-0
doing whatever with stuff now, count=5, threadid=Thread-1
doing whatever with stuff now, count=6, threadid=Thread-0
doing whatever with stuff now, count=7, threadid=Thread-1
doing whatever with stuff now, count=8, threadid=Thread-0
doing whatever with stuff now, count=9, threadid=Thread-1
doing whatever with stuff now, count=10, threadid=Thread-0
doing whatever with stuff now, count=11, threadid=Thread-1
doing whatever with stuff now, count=12, threadid=Thread-0
doing whatever with stuff now, count=13, threadid=Thread-1
doing whatever with stuff now, count=14, threadid=Thread-0
doing whatever with stuff now, count=15, threadid=Thread-1
doing whatever with stuff now, count=16, threadid=Thread-1
doing whatever with stuff now, count=17, threadid=Thread-0
doing whatever with stuff now, count=18, threadid=Thread-1
doing whatever with stuff now, count=19, threadid=Thread-0

请参阅有关受保护块的Oracle教程

非常感谢你们俩。 我会尝试将所有内容写清楚,以使其他陷入类似困境的人可以解决。

我只有2个线程(可以说2个人)。 他们俩都必须从1瓶中喝水,因此在使用该瓶时,第二个人必须等待。 我的代码大致如下所示:

class Bottle{
 private boolean inUse=false;

 public synchronized void getBotttle(String name, int time)  {
    while(inUse) {
      try {
        System.out.println("The bottle is in use. You have to wait");
        wait();
      }
      catch (InterruptedException e) {}
    }

    System.out.println("Person "+name+" is using the bottle");
    inUse = true;
    notify(); //or notifyAll(), tried both

    try {
      Thread.sleep(time); // sleep the Thread with the person that is drinking at the moment for some time in order for him to finish
    }
    catch (InterruptedException e) {}
    System.out.println("The bottle is now free");
    inUse=false;
   // notify(); even if I put it here its still the same
 }
}

我刚开始在Java中使用线程,所以不确定(notify()应该在哪里。 而且我不明白,notify()仅在执行了所有具有关键字synced的块之后才释放锁。 在我的情况下,这不是我想要的,并且在释放锁定时发生,while方法的条件将为false,并且不会执行打印。 程序正在正确等待并按预期进行的事实使我很难发现这一点。

这就是我想要的,也是我正在工作的:

class Bottle{
 private boolean inUse=false;

 public void getBotttle(String name, int time)  {
    while(inUse) {
      try {
        System.out.println("The bottle is in use. You have to wait.");
        synchronized(this){
         wait();
        }
      }
      catch (InterruptedException e) {}
    }

    System.out.println("Person "+name+" is using the bottle");
    inUse = true;

    try {
      Thread.sleep(time); // sleep the Thread with the person that is drinking at the moment for some time in order for him to finish
    }
    catch (InterruptedException e) {}
    System.out.println("The bottle is free now.");
    inUse=false;
    synchronized(this){
     notifyAll();
    }
 }
}

希望最后一次编辑:这应该防止2个线程跳过while循环,应该是我正在寻找的解决方案

class Bottle{
 private boolean inUse=false;

 public synchronized void getBotttle(String name, int time)  {
    while(inUse) {
      try {
        System.out.println("The bottle is in use. You have to wait.");
        wait();
      }
      catch (InterruptedException e) {}
    }

    System.out.println("Person "+name+" is using the bottle");
    inUse = true;
 }

 public synchronized void sleeping(String name, int time)
    try {
      Thread.sleep(time); // sleep the Thread with the person that is drinking at the moment for some time in order for him to finish
    }
    catch (InterruptedException e) {}
    notifyAll();
    System.out.println("The bottle is free now.");
    inUse=false;
 }
}

编辑:不要猜,打印不在使用中的瓶子...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM