6

抱歉,如果这非常明显或已在其他地方得到回答。我什么都没找到。我有以下代码:

public class SimpleThread extends Thread {
    public static Integer sharedVal = 0;
    public SimpleThread() {

    }
    @Override
    public void run() {
       while(true) {           
           iterator();
       }
    }

    public void theSleeper() {
        System.out.println("Thread: " + this.getId() + " is going to sleep!");
        try {
            this.sleep(5000);
        } catch(Exception e) {

        }
    }

    public void iterator() {
        synchronized(sharedVal)  {
            System.out.println("Iterating sharedVal in thread: " + this.getId());
            sharedVal++;
            System.out.println(sharedVal);
            theSleeper();
            System.out.println("Thread : " + getId() + " is done sleeping, trying to iterate again..."); 
        }
    }
}

我创建了这个 SimpleThread 类的两个实例,并执行 run 方法。我希望看到类似:线程 9 递增...线程 9 休眠...(5 秒后)线程 10 递增...。线程 10 休眠...。我希望这是因为我锁定了迭代器方法,以便一次只有一个线程能够进入它。相反,两个线程都递增,然后都等待 5 秒。这永远重复。我在这里错过了什么,这样我才能得到预期的行为?非常感谢!

编辑:我创建了一个新的公共静态变量:public static Object theLock = new Object()。现在,在迭代器方法中,我执行了同步(theLock)。输出现在比我预期的要多,因为锁永远不会改变。但是,现在只有线程 9 进入该方法。似乎线程 10 正在挨饿,并且永远不会转弯。这似乎很奇怪。这不仅仅是几次,它总是只是线程 9 迭代和休眠。我认为它将是 9、10、9、10。或者可能是随机分布,如 9、10、10、10、9、10、9、9、10 等。

EDIT2:我知道现在发生了什么。线程 9 有锁。线程 10 尝试进入函数,但立即被告知等待。函数完成后,可能仍是 Thread 9s 轮回。然后线程 9 重新获取锁,然后循环继续。线程 10 获得一个回合的时间窗口非常小,如果它确实获得了一个回合,它可能会饿死 9。话虽如此,将 yield() 放在 iterator() 中的同步块之后似乎并没有使它更多公平的。我阅读了有关该方法的注释,调度程序实际上可以忽略 yield()。

4

4 回答 4

5

当您进行增量时,您会创建一个新的整数实例和一个用于锁定的新对象。

于 2013-11-04T19:01:32.323 回答
3

您的问题出在此处:

sharedVal++;

由于自动装箱,该行转换为:

sharedVal = Integer.valueOf(sharedVal.intValue() + 1);

它每次运行时都会创建一个新Integer对象,因此每次到达synchronized块时,它都会锁定一个不同的值。

使用专用对象进行同步:

private final static Object LOCK = new Object();

然后将您的同步更改为使用synchronized (LOCK) {...

(你也可以用getClass()锁,但我个人不喜欢将锁对象暴露给公共世界)

于 2013-11-04T19:03:34.537 回答
1

您正在有效地更改线程在每次迭代中使用的锁: ++ on Integer 创建一个新实例(Integer 类是不可变的)

于 2013-11-04T19:01:48.250 回答
0

sharedVal 成员变量实例在您执行 sharedVal++ 时发生变化。相反,您可以使用以下语句进行同步:

同步(SympleThread.class)

于 2013-11-04T19:02:58.817 回答