简体   繁体   English

Java 线程:object 有同步和不同步两种方法

[英]Java Thread : object has both synchronized and not synchronized methods

suppose there are 2 threads used in this demo.Suppose increment() code block executes first and acquires the monitor on the current object.does other thread will not be able to execute the method decrement() ?假设在这个演示中使用了 2 个线程。假设increment()代码块首先执行并获取当前 object 上的监视器。其他线程将无法执行方法decrement()吗? . .

can anyone help me understand?谁能帮我理解?

if I ran the application, other thread able to execute non-synchronized method even though is lock on the object hold by thread that sleeps 10000 ms .如果我运行该应用程序,则其他线程能够执行非同步方法,即使被睡眠10000 ms的线程锁定在 object 上。

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);

    }
}

No, it won't.不,不会的。

  1. synchronized on a method is just syntax sugar for wrapping the entire body of the method in synchronized (X) {} , where X is this for instance methods and YourClass.class for static ones.方法上的synchronized只是将方法的整个主体包装在synchronized (X) {}中的语法糖,其中 X 是this方法, YourClass.class是 static 方法。 It is a severe design error unless you document the locking behaviour of your class if you do this - anytime you lock on stuff other code could get a reference to ( this and YourClass.class are usually public), you need to document this, and endeavour to support what you document in future v ersion.这是一个严重的设计错误,除非您记录 class 的锁定行为,如果您这样做 - 任何时候您锁定其他代码都可以引用的东西( thisYourClass.class通常是公开的),您需要记录这一点,并且努力支持您在未来版本中记录的内容。

  2. synchronized interacts with other synchronized blocks on the same reference, and on thatRef.wait/notify/notifyAll() and nothing else . synchronized与同一个引用上的其他同步块交互,在thatRef.wait/notify/notifyAll()上,没有别的 It has zero effect on its own, you always need 2 different threads both hitting a synchronized block, synchronizing on the same thing, or it does nothing useful.它本身的影响为零,您总是需要 2 个不同的线程同时访问一个同步块,同步同一件事,或者它没有任何用处。

The code snippet as pasted is broken: If some thread calls decrement() , other threads may or may not observe this, as no CBCA relationship is established.粘贴的代码片段已损坏:如果某个线程调用decrement() ,其他线程可能会或可能不会观察到这一点,因为没有建立 CBCA 关系。 Any code that reads sharedVariable needs to lock on ThreadDemo , and the decrement method needs to gain a synchronized attribute.任何读取sharedVariable的代码都需要锁定ThreadDemo ,并且decrement方法需要获得一个synchronized属性。

Note that the job of having an incrementable/decrementable thing already exists: AtomicInteger , you should be using that instead if this is your actual intent (but I'm assuming you wrote this merely as an example).请注意,已经存在具有可递增/可递减事物的工作: AtomicInteger ,如果这是您的实际意图,则应该使用它(但我假设您仅将其编写为示例)。

NB: The java memory model is best understood as an evil coin.注意:java memory model 最好被理解为邪恶的硬币。 Evil in that it is out to mess with you: To have code that works great every time and in all your tests, and the first week you put it live on the production servers, and then just as that important customer gets a demo, it breaks.邪恶在于它会惹恼你:让代码在你的所有测试中每次都运行良好,并且第一周你把它放在生产服务器上,然后就像那个重要的客户得到一个演示一样,它休息。 You must write code such that the VM never flips that coin (or rather, that the results of the flip do not affect your code), and there is no easy way to know that the evil coin is being flipped.您必须编写代码,使 VM 永远不会翻转那个硬币(或者更确切地说,翻转的结果不会影响您的代码),并且没有简单的方法可以知道邪恶的硬币正在被翻转。 Threading is very difficult to get right, yup.线程很难正确处理,是的。 Why do you think most multithreaded code out in the real world does all inter-thread communication via a message bus or transactional database?为什么你认为现实世界中的大多数多线程代码都通过消息总线或事务数据库进行所有线程间通信? The coin is flipped anytime any code touches any field anywhere, and the result of the coin decides whether the thread uses a local clone copy of that field, or if it reads from the shared copy.只要任何代码触及任何地方的任何字段,硬币就会被翻转,硬币的结果决定线程是使用该字段的本地克隆副本,还是从共享副本中读取。 Thus, sharedVariable-- might result in a decrement that only your thread can see, or all threads can see, depending on the result of the evil coin.因此, sharedVariable--可能会导致只有您的线程可以看到或所有线程都可以看到的递减,具体取决于邪恶硬币的结果。 If what your code does depends on the flip, you messed up, and your tests aren't going to catch it.如果您的代码所做的取决于翻转,那么您就搞砸了,并且您的测试不会捕捉到它。 You can avoid the coin flip by establishing a comes-before relationship between sharedVariable-- and whatever cod reads sharedVariable .您可以通过在sharedVariable--和任何 cod 读取sharedVariable之间建立先入为主的关系来避免硬币翻转。 synchronized is one of a few ways to establish such a relationship. synchronized是建立这种关系的几种方法之一。 Search the web for 'java memory model' 'synchronized' for more info - but note that this is very complex stuff.在 web 中搜索“java memory 模型”“同步”以获取更多信息 - 但请注意,这是非常复杂的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM