何时在Java中使用synchronized

use*_*421 10 java android synchronization

我希望这将是足够的信息,所以在这里.如果您需要更多信息,请在评论中了解.

我有一个有两个内部类的类.内部类每个都有两个方法来调用外部类中的方法.所以,它看起来像这样:

public OuterClass {
    private boolean outerMethodHasBeenCalled = false;

    private void outerMethod() {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }

    private FirstInnerClass {
        public void someMethod() {
            outerMethod();
        }
    }

    private SecondInnerClass {
        public void someOtherMethod() {
            outerMethod();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重要的是要注意:

  • 这适用于Android应用.的实例FirstInnerClass,并SecondInnerClass传递给作为网页视图一个JavaScript接口,所以someMethodsomeOtherMethod可以随时调用,没有特定的顺序.
  • 我现在的问题是现有的代码(没有synchronized关键字)outerMethod几乎在同一时间被调用(我打印出一条日志消息,并且它们被加时间戳到1000秒)由不同的对象.我的应用程序然后'做东西'两次,因为outerMethodHasBeenCalledouterMethod被调用时仍然是假的.这不好,这正是我想要阻止的.我的应用程序应该只执行一次"只做一次":第一次outerMethod被调用.
  • 听起来我可能有多个实例OuterClass,但请放心,它只是一个实例OuterClass.

重要的是我的应用程序"只会在第一次outerMethod调用时才会执行操作"(我希望现在这一点很明显).所有后续调用基本上都被忽略.无论哪个内部阶级outerMethod首先调用- 都无关紧要.

那么,在这种情况下使用synchronized关键字是否合适?

bre*_*ttw 19

是的,鉴于你上面列出的内容,我会选择:

private synchronized void outerMethod() {
...
}
Run Code Online (Sandbox Code Playgroud)

注意,这将产生阻止其中一个调用者的副作用,直到outerMethod()完成.如果这是可以接受的,很酷.如果意图仅仅是outerMethod()中的代码运行一次,并且如果第一个调用者运行outerMethod(),则第二个调用者没有延迟是可以的,您可以考虑:

public OuterClass {
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean();

    private void outerMethod() {
        if (outerMethodHasBeenCalled.compareAndSet(false, true)) {
            // do stuff
        }
    }
...
Run Code Online (Sandbox Code Playgroud)

请参阅JavaDoc for AtomicBoolean以了解其中发生的事情(假设它在Android的Java中可用).

  • 为AtomicBoolean +1,学到了新东西:) (9认同)

Bri*_*ham 7

outerMethod包含您想要在同步块中只运行一次的所有内容:

private void outerMethod() {
    synchronized (this) {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,第一次调用该方法时,一次只允许一个线程进入同步块.第一个将在if语句中执行代码,然后设置outerMethodHasBeenCalledtrue.其他线程将看到它是真的,并跳过if代码.

  • 如果访问outerMethodHasBeenCalled的唯一地方是outerMethod,那么@Thilo不需要.synchronized关键字表示内存同步屏障.阅读synchronized关键字上的VM规范.顺便说一下,请不要只是为了"安全起见".准确理解您正在撰写的内容及其含义.在你理解之后进入你的代码的其他程序员将暂时进行侧向跟踪,试图找出使用构造的原因,例如"他必须使用volatile,原因是什么,我没看到什么?" (2认同)
  • "顺便说一下,请不要只是为了安全起见'.确切地了解你所写的内容及其含义."我并不是建议使用volatile来保证安全.恰恰相反:因为低级基元对于凡人来说太复杂了(有时候他们的实现中有错误),我喜欢完全远离`synchronized`或`volatile`并使用更加用户友好的更高 - java.util.concurrent中的级别工具"为安全起见". (2认同)