java - 尽管对象被锁定,但非同步方法仍然可以访问,为什么?

标签 java multithreading synchronization locking

考虑以下因素:

    class A {
    public static void main(String[] args) throws InterruptedException
    {
        final A a = new A();
        new Thread()
        {
            public void run()
            {
                a.intrudeLock();
            };
        }.start();
        Thread.sleep(1000);
        new Thread()
        {
            public void run()
            {
                a.doSomethingAfterLocking();
            };
        }.start();
    }

    synchronized void doSomethingAfterLocking() throws InterruptedException
    {
        System.out.println("aquired lock");
        Thread.sleep(10000);
        System.out.println("finished stuff");
    }

    void intrudeLock()
    {
        System.out.println("don't need object's lock");
    }
}

按照锁定机制 - 预期输出是(至少在大多数情况下):

aquired lock
don't need object's lock
finished stuff

我不是问为什么会出现这个输出,而是理解第二个线程的方法调用不需要锁并因此可以入侵的原因。
现在我有疑问 - 当线程获取锁时,其意图是获得对象的排他性,并且直观地执行环境应该防止其他线程发生任何状态更改。但这不是 Java 的实现方式。这么设计这个机制有什么道理吗?

最佳答案

When a thread acquires lock, its intention is gaining exclusivity over the object and intuitively the execution environment should prevent any state change by other threads. .

小更正:

When a thread acquires lock, its intention is gaining exclusivity over the monitor of the object and intuitively the execution environment should prevent any state change by other threads which are waiting (which need) to acquire the same lock.*

完全由程序员来指定他是否希望仅在获取锁后使用某些字段/资源。如果您有一个字段只能由一个线程访问,那么它不需要同步(获取锁)。

必须注意的重要一点是,完全由程序员根据程序中的代码路径来同步对字段的访问。例如,一个字段可以由一个代码路径中的多个线程访问(需要同步),并且可以仅由另一路径中的一个线程访问。但是,由于不同线程很可能同时访问两个代码路径,因此您应该在进入上述任何代码路径之前获取锁定。

现在,如果 JIT 认为没有必要(例如尝试锁定永远不会逃逸的方法本地字段),则 JIT 可能会决定忽略您的锁定请求(锁定省略)。

关于java - 尽管对象被锁定,但非同步方法仍然可以访问,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35448965/

相关文章:

java - 从不相关的类调用静态同步方法是否安全?

c - 线程变化的开始已经设置了全局变量

java - 套接字一进入新线程就关闭

multithreading - 在Linux/UNIX上的多处理情况下是否可以使用互斥锁?

java - 使用 ConcurrentMap 双重检查锁定

audio - 如何同步两个录音*没有*时间戳?

java - 将布局 GridLayout 的 JPanel 置于另一个 JPanel 中

java - Android获取移动网络频段

java - 使用Jsoup我们如何知道HTML页面中是否存在标签名称

java - 类连接和类语句错误 "cannot find symbol"