我对如何在Java中实现synchronized
块感到困惑。
以下是一个示例情况:
public class SlotWheel extends Thread implements ActionListener
{
private int currentTick; // This instance variable is modified in two places
private synchronized void resetCurrentTicks()
{
currentTick = 0;
}
private synchronized void incrementCurrentTicks()
{
++currentTick;
}
public void actionPerformed(ActionEvent e)
{
resetCurrentTicks();
}
}
当程序运行时,用户可能会点击调用actionPerformed
然后调用resetCurrentTicks
的按钮。同时,正在运行的线程在每次循环迭代时调用incrementCurrentTicks
。
因为我还不熟悉Java和编程,所以我不确定我的实现是否会保护currentTick
不被破坏。
我有这种感觉,我的实现只有在incrementCurrentTicks
和正在运行的线程中调用actionPerformed
时才有效,但是因为我正在用不同的方法操纵currentTick
,我的实施是错误的。
答案 0 :(得分:0)
看起来不错。
请参阅http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
同一个对象上的两个同步方法调用不可能交错
当然你应该考虑是否是GUI线程试图弄乱滴答。在您的简单情况下,它可能没问题,但在更复杂的情况下,您可能希望将“工作”推出GUI线程。
答案 1 :(得分:0)
你的直觉是正确的。跨多个方法一致地同步对类属性的访问很困难。我建议你看看java.util.concurrent.atomic.AtomicInteger,而不是试图这样做。它为您提供了对底层属性的安全,并发访问,而无需编写和测试很多样板代码。
将其合并到您的代码中,最终会得到类似的结果:
public class SlotWheel extends Thread implements ActionListener {
private AtomicInteger currentTick = new AtomicInteger();
private void resetCurrentTicks() {
currentTick.set(0);
}
private void incrementCurrentTicks() {
currentTick.incrementAndGet();
}
public void actionPerformed(ActionEvent e)
{
resetCurrentTicks();
}
}
答案 2 :(得分:0)
首先,Java保证“标量”值 - 整数,字符,浮点数等 - 本身就是原子的,因为你不能同时修改这样的值并得到两个源的混合。您可以保证获得一个值或两个“同时”修改中的另一个值。但是,您可以从例如x++
获得不一致的结果,因为两个线程可能会尝试同时递增x
,并且可能只会发生一个增量。 (OTOH,同时执行x = 7;
的两个线程显然不会相互干扰 - 同时访问不会导致爆炸或任何事情。)
接下来,要了解synchronized
关键字在两个略有不同的上下文中使用 - 作为方法修饰符和块修饰符。两者之间有一些适度的差异。
当用作块修饰符时,您说synchronized(object_ref) {some block}
。在这种情况下,synchronized
语句会锁定object_ref
标识的对象以及可能同时尝试执行引用同一对象的所有其他syncronized
语句在当前声明结束时阻止它。
当你将它用作方法修饰符时,该函数是相同的,除了对于非静态方法,“this”对象是被锁定的对象,并且整个方法被“受保护”锁。
(另一方面,对于静态方法,Class
对象被锁定 - 这是一个稍微特殊的情况,相当于synchronized(ClassName.class){some block}
作为同步块。)
重要的是要理解,要防止两个synchronized
块或方法同时执行,它们必须作为同步对象引用相同的对象,而不仅仅是其中一个同一个班级。
答案 3 :(得分:-1)
你是对的,因为它不安全。但是,您可以简单地在范围内的任何对象上进行同步,并从方法定义中删除“synchronized”
public class MyThread {
private Object lock = new Object();
private int counter;
protected void threadMetod() {
synchronized (lock) {
counter++;
}
}
public void otherReset() {
synchronized (lock) {
counter = 0;
}
}
}