Java 线程:对象同时具有同步和非同步方法

Java Thread : object has both synchronized and not synchronized methods

假设在这个demo.Suppose中使用了2个线程increment()代码块首先执行并获取当前的监视器object.does其他线程将无法执行该方法decrement() ? .

谁能帮我理解一下?

如果我 运行 应用程序,其他线程能够执行非同步方法,即使被睡眠线程持有的对象锁定 10000 ms .

package com.learn.threads;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {

    int sharedVariable;

    public ThreadDemo(int sharedVariable) {
        this.sharedVariable = sharedVariable;
    }


    public synchronized void increment() throws InterruptedException {
        Thread.sleep(10000);
        this.sharedVariable++;

    }

    public void decrement() throws InterruptedException {
        this.sharedVariable--;

    }


    public static void main(String[] args) throws InterruptedException {

        ThreadDemo task = new ThreadDemo(0);

        ExecutorService incrementExecutorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 6; i++) {
            incrementExecutorService.submit(() -> {
                try {
                    task.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            Thread.sleep(5000);
            incrementExecutorService.submit(() -> {
                try {
                    task.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

        }
        Thread.sleep(35000);
        incrementExecutorService.shutdown();
        System.out.println(task.sharedVariable);

    }
}

不,不会。

    方法上的
  1. synchronized 只是语法糖,用于将方法的整个主体包装在 synchronized (X) {} 中,其中 X 是 this 实例方法和 YourClass.class 对于静态的。这是一个严重的设计错误,除非你记录了 class 的锁定行为,如果你这样做 - 任何时候你锁定其他代码可以引用的东西(thisYourClass.class 通常是public),您需要对此进行记录,并努力在未来的版本中支持您记录的内容。

  2. synchronized 在同一引用上与其他同步块交互,在 thatRef.wait/notify/notifyAll() 上没有其他任何东西 。它本身的影响为零,你总是需要 2 个不同的线程同时触发一个同步块,在同一事物上同步,否则它什么也没做。

粘贴的代码片段已损坏:如果某些线程调用 decrement(),其他线程可能会也可能不会观察到这一点,因为没有建立 CBCA 关系。任何读取 sharedVariable 的代码都需要锁定 ThreadDemo,并且 decrement 方法需要获得一个 synchronized 属性。

请注意,拥有 incrementable/decrementable 的工作已经存在:AtomicInteger,如果这是您的实际意图,您应该使用它(但我假设您只是将其写为一个例子)。

注意:java内存模型最好理解为邪恶的硬币。邪恶之处在于它会惹恼你:让代码在你所有的测试中每次都运行良好,第一周你把它放在生产服务器上,然后当那个重要的客户得到一个演示时,它休息。您必须编写代码,使 VM 永远不会抛硬币(或者更确切地说,抛硬币的结果不会影响您的代码),并且没有简单的方法可以知道正在抛硬币。线程很难正确,是的。为什么您认为现实世界中的大多数多线程代码都全部 通过消息总线或事务数据库进行线程间通信?任何时候任何代码接触任何地方的任何字段都会抛硬币,硬币的结果决定线程是使用该字段的本地克隆副本,还是从共享副本读取。因此,sharedVariable-- 可能会导致只有您的线程可以看到或所有线程都可以看到的减量,具体取决于邪恶硬币的结果。如果你的代码做什么取决于翻转,你就搞砸了,你的测试不会捕捉到它。您可以通过在 sharedVariable-- 和任何 cod 读取 sharedVariable 之间建立先行关系来避免抛硬币。 synchronized 是建立这种关系的几种方法之一。在网络上搜索 'java memory model' 'synchronized' 以获取更多信息 - 但请注意,这是非常复杂的内容。