是id = 1 – idprimefaces?

从OCP Java SE 6程序员实践考试第291页,问题25:

public class Stone implements Runnable { static int id = 1; public void run() { id = 1 - id; if (id == 0) pick(); else release(); } private static synchronized void pick() { System.out.print("P "); System.out.print("Q "); } private synchronized void release() { System.out.print("R "); System.out.print("S "); } public static void main(String[] args) { Stone st = new Stone(); new Thread(st).start(); new Thread(st).start(); } } 

其中一个答案是:

输出可以是PQPQ

我标记这个答案是正确的。 我的推理:

  1. 我们开始两个线程。
  2. 首先进入run()
  3. 根据JLS 15.26.1 ,它首先评估1 - id 。 结果是0 。 它存储在线程的堆栈中。 我们正要将0保存为静态id ,但是…
  4. 繁荣,调度select第二个线程运行。
  5. 所以,第二个线程进入run() 。 静态id仍然是1 ,所以他执行pick()方法。 打印PQ
  6. 调度程序select第一个线程运行。 它从堆栈中取0 ,并保存到静态id 。 所以,第一个线程也执行pick()并打印PQ

然而,在书中写道,这个答案是不正确的:

这是不正确的,因为行id = 1 - id交换01之间的id的值。 相同的方法没有机会被执行两次。

我不同意。 我想上面提到的场景有一些机会。 这种交换不是primefaces的。 我错了吗?

我错了吗?

不,你是绝对正确的 – 正如你的例子时间表。

除了不是primefaces的,不能保证write的id会被其他线程拿走,因为没有同步,而且字段也不是不稳定的。

像这样的参考资料是不正确的有点令人不安

在我看来,实践考试的答案是正确的。 在这段代码中,你正在执行两个可以访问相同静态variablesid的线程。 静态variables存储在java中的堆中,而不是堆栈中。 runnables的执行顺序是不可预知的。

但是,为了改变每个线程的id值:

  1. 使存储在ID的存储器地址中的值的本地副本到CPUregistry;
  2. 执行操作1 - id 。 严格来说,这里执行两个操作(-id and +1) ;
  3. 将结果移回到堆的id内存空间。

这意味着虽然id值可以被两个线程中的任何一个同时改变,但是只有初始值和最终值是可变的。 中间值不会彼此修改。

此外,对代码的分析可以表明,在任何时候,id只能是0或1。

certificate:

  • 起始值id = 1; 一个线程会将其更改为0( id = 1 - id )。 而另一个线程将把它带回到1。

  • 起始值id = 0; 一个线程会将其更改为1( id = 1 - id )。 而另一个线程将把它带回到0。

因此,id的值状态是离散的0或1。

结束certificate。

这个代码有两种可能性:

  • 可能性1.线程先访问variablesID。 然后,id( id = 1 - id值变为0.此后,只有方法pick ()会被执行,打印PQ 。线程2,会在这个时候评估id = 0 ;方法release()执行打印R S。结果, PQRS将被打印。

  • 可能性2.首先访问两个variablesid。 然后,id( id = 1 - id值变为0.此后,只有方法pick ()会被执行,打印PQ 。线程1,将在此时评估id = 0 ;方法release()执行打印R S。结果, PQRS将被打印。

没有其他的可能性。 但是,应该注意的是,由于pick()是一个静态方法,所以可以打印诸如PRQSRPQS等的PQRS变体,因此在两个线程之间共享。 这会导致同时执行此方法,这可能导致根据您的平台以不同的顺序打印字母。

然而在任何情况下, pick()release ()不会执行两次,因为它们是互斥的 。 所以PQPQ不会是输出。