Java同步混淆
很抱歉,如果这是非常明显的,或者已经在其他地方得到了回答。我什么也没找到。我有以下代码:Java同步混淆,java,concurrency,Java,Concurrency,很抱歉,如果这是非常明显的,或者已经在其他地方得到了回答。我什么也没找到。我有以下代码: public class SimpleThread extends Thread { public static Integer sharedVal = 0; public SimpleThread() { } @Override public void run() { while(true) { itera
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秒钟。这种情况永远重复。我在这里遗漏了什么,这样我就能得到预期的行为?非常感谢
编辑:我创建了一个新的公共静态变量:publicstaticobjectthelock=newobject()。现在,在迭代器方法中,我进行了同步(锁定)。输出现在比我预期的要多,因为锁永远不会改变。但是,现在只有线程9进入该方法。线程10似乎正在挨饿,而且从来没有轮到它。这似乎很奇怪。这不仅仅是几次,它总是只是线程9的迭代和休眠。我想应该是9,10,9,10。或者像9,10,10,10,9,10,9,9,10这样的随机分布
EDIT2:我知道现在发生了什么。螺纹9有锁。线程10试图进入函数,但被立即告知等待。函数完成后,可能仍要轮到线程9。然后线程9重新请求锁,循环继续。线程10获得一个回合的时间窗口非常小,如果它确实获得了一个回合,它可能会饿死9。也就是说,在迭代器()中,将yield()放在synchronized块之后似乎不会使它更公平。我阅读了关于该方法的评论,调度器实际上可以忽略yield() 执行增量操作时,您将创建一个新的integer实例和一个新的锁定对象。您将有效地更改线程在每次迭代中使用的锁定:++on integer创建一个新实例(integer类是不可变的)执行sharedVal++时,sharedVal成员变量实例正在更改。相反,您可以使用以下语句进行同步:
已同步(SympleThread.class)您的问题在这里:
sharedVal++;
由于自动装箱,这一行转化为:
sharedVal = Integer.valueOf(sharedVal.intValue() + 1);
它每次运行时都会创建一个新的Integer
对象,因此每次调用synchronized
块时,它都会锁定一个不同的值
使用专用对象进行同步:
private final static Object LOCK = new Object();
然后将同步更改为使用synchronized(LOCK){…
(您也可以使用
getClass()
进行锁定,但我个人不喜欢将锁定对象公开给公众)@OP:请使用可更改的东西(如StringBuilder)重试(因为StringBuffer是同步的,所以不是StringBuffer)我完全同意,我觉得自己很傻。我不知道为什么整数是不可变的,但这是另一个问题。请查看我的编辑。锁定。等待(5000);事实上,根本不等待。我尝试了锁定和锁定,但我认为您指的是我的锁定。然而,这是交替的9和10。这可能只是睡眠的一个非常严重的时间问题,尽管我想理解为什么10真的会挨饿?很高兴知道事实上…但当它退出同步块时应该发布,对吗?就像我的代码中的迭代器()有一个同步块,其中包含睡眠函数调用。非常感谢您的帮助,这是一个很好的解释。是的,另一个也提到了这一点,感谢您指出此错误。请查看我的编辑是的,感谢您指出我的错误。请查看我的编辑,谢谢!当线程9从睡眠中恢复时,它将释放e锁,然后重新获取它,使线程10没有任何可能性。它唯一的机会是调度程序在锁之间停止线程9,这是不可能的。在迭代之间添加thread.yield()
,这将使事情变得更公平。是的,我现在看到了这一点,并将其添加到我的第二次编辑中。thread.yield()似乎没有多大帮助,因为调度程序可能忽略了它。尽管如此,我想我现在理解得更多了。非常感谢!自动装箱是一个魔鬼哈哈,似乎它可能会有问题!:)