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 个线程具有 "bottle" 但打印不存在。
有什么想法吗?
有效的答案非常简单,您的 getBotttle()
方法的签名有关键字 synchronized
这意味着永远不会有两个不同的线程同时访问此代码。所以,while(myCondition) { ... }
的整个块是没有结果的。
其次,我建议您查看 java.util.concurrent.*
软件包。
更新。似乎值得澄清一下 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
非常感谢你们。我会尽量把所有的事情都写清楚,这样其他陷入类似问题的人就可以解决。
我有 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() 只有在执行了所有具有关键字 synchronized 的块后才释放锁。在我的例子中,这不是我想要的,当锁被释放时,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;
}
}
编辑:
猜猜不是,打印正在使用的瓶子不会再次执行...
我正在尝试实现一个只有一个线程可以访问的条件:假设它是一瓶水——我希望只有一个人(线程)能够一次喝到它。一切似乎都很顺利,但我无法显示打印结果 - 调用 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 个线程具有 "bottle" 但打印不存在。 有什么想法吗?
有效的答案非常简单,您的 getBotttle()
方法的签名有关键字 synchronized
这意味着永远不会有两个不同的线程同时访问此代码。所以,while(myCondition) { ... }
的整个块是没有结果的。
其次,我建议您查看 java.util.concurrent.*
软件包。
更新。似乎值得澄清一下 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
非常感谢你们。我会尽量把所有的事情都写清楚,这样其他陷入类似问题的人就可以解决。
我有 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() 只有在执行了所有具有关键字 synchronized 的块后才释放锁。在我的例子中,这不是我想要的,当锁被释放时,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;
}
}
编辑: 猜猜不是,打印正在使用的瓶子不会再次执行...