Java线程忙等待

时间:2015-04-25 23:18:14

标签: java multithreading busy-waiting

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

该项目希望发生以下情况:早上,在学生醒来后(需要一段随机时间),他将前往卫生间为新的上学日做好准备。如果浴室已经被带走,学生休息一下(使用yield()),之后他将等待(使用忙碌的等待)浴室可用。学生将以先到先得的方式使用浴室(您可以使用布尔数组/向量按顺序发布)。

 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;

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

 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();
   }

1 个答案:

答案 0 :(得分:0)

这是一个繁忙等待的工作示例。它使用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,否则两个线程有​​可能在(1)执行(2)之前成功完成测试(因为这两个操作不是 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毫秒 爱丽丝睡了1289毫秒 彼得睡了820毫秒 德斯蒙德睡了1878毫秒 索菲亚睡了2274毫秒 彼得去洗手间 彼得在浴室里 爱丽丝去洗手间 爱丽丝休息一下 彼得上大学 德斯蒙德去洗手间 Desmond在浴室里 鲍勃去洗手间 鲍勃休息一下 索菲亚去洗手间 索菲亚休息一下 爱丽丝休息一下 德斯蒙德上大学 鲍勃在浴室里 索菲亚休息一下 爱丽丝休息一下 玛西娅去洗手间 玛西娅休息一下 鲍勃上大学 索菲亚在浴室里 爱丽丝休息一下 玛西娅休息一下 索菲亚上大学 爱丽丝在浴室里 玛西娅休息一下 爱丽丝上大学 玛西娅在浴室里 玛西娅上大学