简体   繁体   English

这些类是否是线程安全的?

[英]Are these classes thread-safe?

First class: 头等舱:

class Main1 {
    private ExecutorService service = Executors.newFixedThreadPool(4);

    public static void main(String[] args) {
       Main1 m = new Main1();
       m.start();
    }

    public void start() {
        final MyObject obj = new MyObject(); 
        obj.doSomeCalculation();//  after this point not to modify obj in main thread

        service.submit(new Runnable(){
            public void run() {
                    obj.doSomething(); // is it threadsafe doing this?
               }
        });
    }
}

Second class: 二等:

class Main2 {
    private ExecutorService service = Executors.newFixedThreadPool(4);

    public static void main(String[] args) {
        Main2 m = new Main2();
        m.start();
    }

    public void start() {
        class Job implements Runnable {
           public MyObject obj;

            public void run() {
                obj.doSomething(); // is it threadsafe doing this?
            }
        }

        Job job = new Job();
        job.obj.doSomeCalculation(); // after this point not to modify obj in main thread
        service.submit(job);
    }
}

Are Main1 and Main2 threadsafe? Main1Main2线程是否安全? Does Main1 and Main2 make different sense to thread-safety? Main1和Main2对线程安全有不同的意义吗?

update: neither doSomeCalulation() nor doSomething() don't have any lock or synchronized block. 更新:doSomeCalulation()和doSomething()都没有任何锁定或同步块。 I want to known whether doSomething() could always read the correct states that doSomeCalculation() change to obj 我想知道doSomething()是否总能读取doSomeCalculation()更改为obj的正确状态

Are Main1, Main2 threadsafe? Main1,Main2线程是否安全?

In the Main1 case, the thread-safety of the application depends on whether MyObject is thread-safe and whether any other threads doing things with it. Main1情况下,应用程序的线程安全性取决于MyObject是否是线程安全的以及是否有任何其他线程使用它。 However, the obj.doSomething(); 但是, obj.doSomething(); statement is thread-safe assuming nothing else is changing the object 语句是线程安全的,假设没有其他东西正在改变对象

In fact, the obj.doSomething(); 实际上, obj.doSomething(); statement doesn't use the variable in the enclosing class. 语句不使用封闭类中的变量。 Instead, the value of that variable is passed to the inner class in a hidden constructor argument. 相反,该变量的值将传递给隐藏构造函数参数中的内部类。 The other thing that makes this thread-safe is that there is an implicit synchronization between the parent and child threads when a new thread is created. 使线程安全的另一个原因是在创建新线程时父线程和子线程之间存在隐式同步。 (Reference - JLS 17.4.4 Synchronization Order ) These two facts combined mean that the Runnable.run() method will get the correct reference, and that the child thread will see the state of the object at the synchronization point (or later). (参考 - JLS 17.4.4同步顺序 )这两个事实相结合意味着Runnable.run()方法将获得正确的引用,并且子线程将在同步点(或更高版本)看到对象的状态。

In the Main2 case, the same applies. Main2案例中,同样适用。 In this case you are merely doing explicitly (more or less) what is happening implicitly in the Main1 case. 在这种情况下,您只是明确地(或多或少)明确地在Main1案例中发生了Main1

UPDATE - the above reasoning applies even if you mutate the object in the parent thread (as per your updated question) before passing it to the child thread ... because of the implicit synchronization that I mentioned. 更新 - 即使您在将父对象中的对象(根据您更新的问题)变更之前,上面的推理也适用,然后再将其传递给子线程......因为我提到了隐式同步。 (However, if the parent thread were to change MyObject after the submit() call, you'd run into thread-safety problems.) (但是,如果父线程在submit()调用之后更改MyObject ,则会遇到线程安全问题。)

Does Main1 and Main2 make different sense? Main1和Main2有不同的含义吗?

I don't know what you are asking. 我不知道你在问什么。 If you are asking if there is any benefit in using an inner class rather than an anonymous inner class ... in this case the answer is no. 如果你在询问使用内部类而不是匿名内部类是否有任何好处...在这种情况下答案是否定的。 They behave the same with respect to thread-safety. 它们在线程安全方面表现相同。

Actually, the Main1 version is better because its is simpler, more readable (to an experienced Java developer), and more robust. 实际上, Main1版本更好,因为它更简单,更易读(对于有经验的Java开发人员),并且更加健壮。 The Main2 class exposes the obj field for other code to potentially access or even update. Main2类公开了其他代码的obj字段,可能会访问甚至更新。 That's bad style. 这是糟糕的风格。 You could fix that, but only by adding more code ... which brings us back to simplicity / readability. 你可以解决这个问题,但只能添加更多代码......这将我们带回简单/可读性。

The way your code is structured, you submit your job (in both cases) only after you have already performed the calculation above. 您的代码的结构方式,只有在您完成上述计算后才能提交您的工作(在这两种情况下)。 So there is no chance of those two actions happening in parallel and so there are no data races. 因此,这两个动作不可能并行发生,因此没有数据竞争。

However, if you were to perform your calculations after submitting the job/Runnable to the executor service, then those two calculations could happen in parallel and there could be a data race. 但是,如果您将作业/ Runnable提交给执行程序服务执行计算,则这两个计算可能会并行发生,并且可能存在数据争用。

Job job = new Job();
service.submit(job);
// Now there is a data race!!!
job.obj = ...// do some calculation, and after this point not to modify obj in main thread

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

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