java - 如何确保线程调用 wait() 之后发生事件?

标签 java multithreading synchronization producer-consumer

我有 Golfer 线程的当前 run() 方法:

public void run() {
  while (done.get() != true) { // this is just a flag to see if the GolfRange is open
    synchronized (sharedStash) {

      System.out.println(">>> Golfer #" + myID
          + " trying to fill bucket with " + getBallsPerBucket() + " balls.");
      while (sharedStash.getSizeStash().intValue() < 5) {

        try {
          System.out.println(myID + "is still waiting, size = "
              + sharedStash.getSizeStash().intValue());
          sharedStash.wait(1000);

        } catch (InterruptedException ex) {
          Logger.getLogger(Golfer.class.getName())
              .log(Level.SEVERE, null, ex);
        }
      }

      golferBucket = sharedStash.getBucketBalls();
      System.out.println("<<< Golfer #" + myID + " filled bucket with "
          + getBallsPerBucket() + " balls, size = "
          + sharedStash.getSizeStash());
    }
  }
}

sharedStash 是一个对象,表示由 Golfer 和随机时间“拾起”高尔夫球的线程共享的 golfBall 对象的集合。

我想做的事情:

显然,如果sharedStash的大小小于5,高尔夫球手就无法拿起一桶球,必须等到收集器线程退出并将球添加回sharedStash

例如,当前 sharedStash 大小为 3,并且 Golfer 线程“Bob”正在尝试填满他的球桶。他必须等到 Collector 线程从场上收集球并将它们添加到 sharedStash 中。但目前发生的情况是,当高尔夫球手线程“鲍勃”试图填满他的水桶时,它只会打印:“高尔夫球手鲍勃正在尝试填满他的水桶”,然后其他桶中有球的线程开始撞击,直到收集器线程来到高尔夫球场,收集球,将它们添加到 sharedStash 中。如果收集器添加的数量超过 5,应该发生高尔夫球手鲍勃应该任何其他高尔夫球手线程之前拿到他的水桶。

但是,现在发生的情况是,即使鲍勃等待的时间最长,其他高尔夫球手也会在“鲍勃”之前填满。

我该如何解决这个问题?

示例:

>>> Golfer #1 trying to fill bucket with 5 balls.
<<< Golfer #1 filled bucket with 5 balls, size = 15
>>> Golfer #5 trying to fill bucket with 5 balls.
<<< Golfer #5 filled bucket with 5 balls, size = 10
>>> Golfer #2 trying to fill bucket with 5 balls.
<<< Golfer #2 filled bucket with 5 balls, size = 5
>>> Golfer #3 trying to fill bucket with 5 balls.
<<< Golfer #3 filled bucket with 5 balls, size = 0
>>> Golfer #4 trying to fill bucket with 5 balls.
Golfer #1 hit ball #1 onto field.
Golfer #3 hit ball #16 onto field.
Golfer #5 hit ball #6 onto field.
Golfer #1 hit ball #2 onto field.
Golfer #2 hit ball #11 onto field.
*********** Bollie collecting balls   ************
*********** Bollie adding 5 balls to stash ************
*********** Bollie added 5 balls to stash ************
Current stash size: 5
Golfer #1 hit ball #3 onto field.
Golfer #2 hit ball #12 onto field.
Golfer #3 hit ball #17 onto field.
Golfer #5 hit ball #7 onto field.
Golfer #1 hit ball #4 onto field.
Golfer #2 hit ball #13 onto field.
Golfer #1 hit ball #5 onto field.
>>> Golfer #1 trying to fill bucket with 5 balls.
<<< Golfer #1 filled bucket with 5 balls, size = 0
Golfer #2 hit ball #14 onto field.
Golfer #5 hit ball #8 onto field.
*********** Bollie collecting balls   ************
*********** Bollie adding 9 balls to stash ************
*********** Bollie added 9 balls to stash ************
Current stash size: 9
Golfer #5 hit ball #9 onto field.
Golfer #3 hit ball #18 onto field.
Golfer #1 hit ball #1 onto field.
Golfer #1 hit ball #16 onto field.
Golfer #2 hit ball #15 onto field.
>>> Golfer #2 trying to fill bucket with 5 balls.
<<< Golfer #2 filled bucket with 5 balls, size = 4
Golfer #1 hit ball #6 onto field.
BUILD STOPPED (total time: 7 seconds)

最佳答案

您的代码没有努力建立排队系统。你希望高尔夫球手排队等候,对吗?因此,当需要上线时,实际上让高尔夫球手加入队伍,也称为 BlockingQueue .

BlockingQueue 作为构造函数的一部分传递到每个 Runnable 中。在这种情况下,您甚至不需要使用 synchronized 关键字,因为您将阻止 poll 方法。换句话说,在 Golfer 线程上:

private BlockingQueue<Bucket> queue;

public void getMoreBalls() {
    queue.poll(ballQueue);
}

在 Bollie 线程上:

private BlockingQueue<Bucket> queue;

public void addBucketToQueue() {
   queue.offer(new Bucket());
   stash -= 5;
}

显然,这不是完整的代码,但我认为您可以自己充实它。

关于java - 如何确保线程调用 wait() 之后发生事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32149762/

相关文章:

java - 如何将使用数据库的java桌面应用程序导出到其他电脑?

java - 使用 @Async 注释限制线程数并在达到最大线程数时等待

c++ - Qt中不同线程中的对象同步

c# - 在同步框架中配置适配器

java - 如何让 ExecutorService 中的线程进入等待阶段

java - Android Canvas ,保存/恢复绘画设置

java - 使用 ByteBuddy 重新定义 java.lang 类

c# - 异步线程

java - 私有(private)锁对象和内在锁

Java线程-同步问题