Java 个线程正忙于等待

Java Threads Busy Waiting

嗨,我正在做一个项目,我已经到了一个非常卡住的部分。我试图寻找方法来学习如何为繁忙的等待编写 while 循环,但我没有找到任何东西,我的代码只是作为一个无限循环运行。有人可以帮我解释一下繁忙的等待循环应该如何工作并帮助我摆脱这个无限循环吗?

该项目希望发生以下情况:早上,学生醒来后(需要随机时间)他将前往洗手间为新的上学日做准备。如果洗手间已经有人了,学生会休息一下(使用 yield()),稍后他将等待(使用忙碌等待)洗手间可用。学生将以先到先得的方式使用洗手间(您可以使用布尔值 array/vector 让他们按顺序释放)。

 public class Student implements Runnable 
    {
        private Random rn = new Random();
        private String threadNum;
        private volatile boolean bathroomFull = false;
        private static long time = System.currentTimeMillis();
        private Thread t;


    public Student(String studentID) 
    {
      threadNum = studentID;

      t = new Thread(this, "Student Thread #"+threadNum);
      System.out.println("thread created = " + t);
      // this will call run() function
      t.start();
   }

   public void run() 
   {
       int waitTime = rn.nextInt(4000 - 2000 + 1)+2000;

        System.out.println( "the current time is " + (System.currentTimeMillis() - time) + "and the wait time is: " +waitTime );

         //Student wakes up after random time
        while((System.currentTimeMillis()-time) < waitTime)
       {
          // System.out.println("the remaining sleep time is " + (System.currentTimeMillis()-time));
            ;
       }

      int a = rn.nextInt(4000 - 2000 + 1)+2000;
      try 
      {
          //System.out.println("I'm going to sleep for " +a + " milliseconds");
        Thread.sleep(a);
      } 
      catch (InterruptedException e) 
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      //this is the busy wait loop where is the bathroom is full then a thread will yield until it is available
    int l = rn.nextInt(10 - 1)+1;
  bathroomFull = true;

      while(bathroomFull)
        {
          for(int j = 0; j < l; j++)
          {
              System.out.println("i am in the bathroom for " + l + "minutes " + Thread.currentThread());
          }
          Thread.yield();
          bathroomFull = false;
          //exitBathroom();

        }
    bathroomFull = true;

这是我的主要方法,它允许用户指定他们想要的学生线程数。是的,我不明白如何实现值的更改,以便可以打破繁忙的 wait while 循环。

 public static void main(String args[]) 
   {
       int numberOfStudents;
       numberOfStudents = Integer.parseInt(JOptionPane.showInputDialog("How many students are there in the university? "));
      // System.out.println("there are " + numberOfStudents);

       for(int i = 0; i < numberOfStudents; i++)
       {   
           new Student(String.valueOf(i+1));
       }
          new Teacher();
   }

这是一个忙等待的工作示例。它使用 AtomicBoolean 来指示浴室是否有人。原子操作一步执行,这对保证线程安全很重要。我们也可以使用普通布尔值并自己编写 compareAndSet

private static synchronized boolean compareAndSet(boolean expected, boolean value) {
    if (occupied == expected) { // (1)
        occupied = value; // (2)
        return true;
    } else {
        return false;
    }
}

这与 Java 实现等效(对于本例)。 synchronized 是必需的,否则在执行 (2) 之前,两个线程可能会在 (1) 处成功通过测试(因为这两个操作不是 atomic) 然后两个人一起去洗手间...

import java.util.concurrent.atomic.AtomicBoolean;

public class Student extends Thread {

    // note the static: there is only one bathroom for all students
    private static AtomicBoolean occupied = new AtomicBoolean(false);

    private String name;

    public Student(String name) {
        this.name = name;
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            System.out.println(name + " wet his/her pants");
        }
    }

    @Override
    public void run() {
        int r = (int)(Math.random() * 5000);
        System.out.println(name + " sleeps for " + r + " ms");
        sleep(r);
        System.out.println(name + " goes to bathroom");
        // ***** busy wait *****
        while (!occupied.compareAndSet(false, true)) {
            System.out.println(name + " takes a break");
            Thread.yield();
            sleep(1000);
        }
        // ***** end (in bathroom) *****
        System.out.println(name + " is in the bathroom");
        sleep(1000);
        occupied.set(false);
        System.out.println(name + " goes to university");
    }

    public static void main(String[] args) {
        new Student("Bob").start();
        new Student("Alice").start();
        new Student("Peter").start();
        new Student("Marcia").start();
        new Student("Desmond").start();
        new Student("Sophia").start();
    }

}

可能的输出:

鲍勃睡了 2128 毫秒
玛西娅睡了 3357 毫秒
Alice 睡了 1289 毫秒
彼得睡了 820 毫秒
Desmond 睡了 1878 毫秒
索菲亚睡了 2274 毫秒
彼得去洗手间
彼得在洗手间
爱丽丝去洗手间
爱丽丝休息一下
彼得上大学
Desmond 去洗手间
Desmond 在洗手间
鲍勃去洗手间
鲍勃休息一下
索菲亚去洗手间
索菲亚休息一下
爱丽丝休息一下
戴斯蒙德上大学
Bob 在洗手间
索菲亚休息一下
爱丽丝休息一下
玛西娅去洗手间
玛西娅休息一下
鲍勃上大学
索菲亚在洗手间
爱丽丝休息一下
玛西娅休息一下
索菲亚上大学
爱丽丝在洗手间
玛西娅休息一下
爱丽丝上大学
玛西娅在洗手间
玛西娅上大学