2017-04-24 64 views
0

Main.java:具有最高优先级的Java线程没有得到执行

public class Main { 
    public static void main(String[] args) { 
     final Semaphore semp = new Semaphore(1); 
     for (int facultyNO = 1; facultyNO <= 10; facultyNO++) { 
      final int NO = facultyNO; 
      Runnable run = new Runnable() { 
       public void run() { 
        try { 
         while (true) { 
          semp.acquire(); 
          System.out.println("No." + NO + " grab a candy"); 
          Bowl.candy--; 
          System.out.println("Candy num left:" + Bowl.candy); 
          semp.release(); 
          Thread.sleep((long) (1000)); 
         } 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      }; 
      Thread faculty = new Thread(run); 
      faculty.setPriority(Thread.MIN_PRIORITY); 
      faculty.start(); 
     } 
     Thread TA = new Thread(() -> { 
      try { 
       while (true) { 
        if (Bowl.candy < 0) { 
         semp.acquire(); 
         System.out.println("TA fills the candy bowl"); 
         Bowl.candy = 10; 
         System.out.println("Candy num left:" + Bowl.candy); 
         semp.release(); 
        } 
       } 
      }catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     }); 
     TA.setPriority(Thread.MAX_PRIORITY); 
     TA.start(); 
    } 
} 

Bowl.java:

public class Bowl { 
    static int candy = 10; 
} 

我给线程 “TA” 最高优先级,因为我希望它只要Bowl.candy = 0就可以立即执行以填充碗。但是,控制台打印:

No.2 grab a candy 
Candy num left:9 
No.1 grab a candy 
Candy num left:8 
No.4 grab a candy 
Candy num left:7 
No.6 grab a candy 
Candy num left:6 
No.7 grab a candy 
Candy num left:5 
No.8 grab a candy 
Candy num left:4 
No.3 grab a candy 
Candy num left:3 
No.5 grab a candy 
Candy num left:2 
No.10 grab a candy 
Candy num left:1 
No.9 grab a candy 
Candy num left:0 
No.2 grab a candy 
Candy num left:-1 
No.1 grab a candy 
Candy num left:-2 
No.4 grab a candy 
Candy num left:-3 
No.6 grab a candy 
Candy num left:-4 
No.7 grab a candy 
Candy num left:-5 
No.8 grab a candy 
Candy num left:-6 
No.3 grab a candy 
Candy num left:-7 
No.5 grab a candy 
Candy num left:-8 
No.10 grab a candy 
Candy num left:-9 
No.9 grab a candy 
Candy num left:-10 

好像if (Bowl.candy < 0)从未得到执行中的代码。为什么?

+4

线程优先级不是操作系统调度程序遵循的硬规则。如果你有线程间依赖性(就像一个线程应该在其他线程之前执行)那么基本上你不需要线程。线程专门处理计算可以独立完成的事实。如果您正在寻找线程之间的共享状态,则需要使用其他并发机制。这可能会帮助你更多http://stackoverflow.com/questions/8811535/inconsistent-results-with-java-threads – kosa

回答

3

你必须在这种情况下访问变量之前获取锁:

semp.acquire(); 
if (Bowl.candy < 0) { 
    System.out.println("TA fills the candy bowl"); 
    Bowl.candy = 10; 
    System.out.println("Candy num left:" + Bowl.candy); 
} 
semp.release(); 

另一种选择:

Bowl.candy都将被声明为volatile否则就不能保证其他线程可以看到更改这个变量。或Bowl.candy必须仅在​​块中进行访问。

+0

这不是信号量在做什么? – Michael

+0

@Michael,信号量在获取变量后保证可见性。但是你在获得锁之前访问'Bowl.candy':'if(Bowl.candy <0){semp.acquire(); ...',所以它总是看到 – vhula

1

我怀疑这是一个竞态条件问题。你正在检查这个值,然后我怀疑另一个线程已经占用了信号量,所以你不能改变它的值。

如果您更改信号量来包装支票和作业,您的结果会稍微好一些。

Thread TA = new Thread(() -> { 
    try { 
     while (true) { 
      semp.acquire(); 
      if (candy < 0) { 
       System.out.println("TA fills the candy bowl"); 
       Bowl.candy = 10; 
       System.out.println("Candy num left:" + Bowl.candy); 
      } 
      semp.release(); 
     } 
    } 
    //... 
}); 

但是,由于时间安排问题,你会得到的结果是这样的:

Candy num left:2 
No.2 grab a candy 
Candy num left:1 
No.3 grab a candy 
Candy num left:0 
No.5 grab a candy 
Candy num left:-1 //!!! 
No.6 grab a candy 
Candy num left:-2 //!!! 
TA fills the candy bowl 

由于Nambari指出的那样,你可能不希望与多线程来解决这个问题。

+0

谢谢。我试过你的解决方案,它的工作!每次糖果= 0时,它都会被填满。我不知道为什么会发生这种情况...... –

+0

@XINDILI:如果解决方案适合您,您需要接受答案。 – kosa

+0

@XINDILI我会带一点盐。多次运行它以验证它是否符合您的期望。也许写一个单元测试。我认为,你所希望的最好的一点是它依赖于平台。我已经目睹它不适合自己(低于零),所以危险肯定存在。 – Michael