Java同步混乱

use*_*279 6 java concurrency

对不起,如果这是非常明显或已在其他地方回答.我找不到任何东西.我有以下代码:

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..."); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

编辑2:我看到现在发生了什么.线程9具有锁定.线程10尝试进入该功能,但是立刻被告知等待.函数完成后,它可能仍然是线程9转.线程9然后重新获得锁定,并且循环继续.线程10获得转弯的时间窗口非常小,如果它确实转了,它可能会饿死9.这就是说,在iterator()中的synchronized块之后放置yield()似乎没有让它更多公平.我阅读了关于该方法的注释,并且调度程序实际上可以忽略yield().

ans*_*oyt 5

在进行增量时,可以创建一个新的整数实例和一个用于锁定的新对象.


Dar*_*ogg 3

你的问题出在这里:

sharedVal++;
Run Code Online (Sandbox Code Playgroud)

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

sharedVal = Integer.valueOf(sharedVal.intValue() + 1);
Run Code Online (Sandbox Code Playgroud)

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

使用专用对象进行同步:

private final static Object LOCK = new Object();
Run Code Online (Sandbox Code Playgroud)

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

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