什么对象需要同步?为什么局部变量不好?

huangapple go评论89阅读模式
英文:

What objects to synchronize on? Why are local variables bad?

问题

关于同步问题,Stack Overflow 上有很多相关材料,但我仍然没有找到有关选择哪个对象用作内在锁的高质量内容。有人可以制定一个经验法则来提供良好的答案吗?

那么,我应该选择将 'monitor' 作为实例变量、局部变量还是拥有该方法的实例?这三者都可以胜任工作。此外,原始值包装类使用 'pools',因此在这方面也没有问题,因为线程“攻击”相同的锁。

那么为什么最好这样做(这样):

class A {
    void methodA(){
        synchronized (this){
            //一些代码    
        }
    }
}

而不是这样(实例变量):

class A {
    String monitor = "monitor";
    void methodA(){
        synchronized (monitor){
            //一些代码
        }
    }
}

或者这样(局部变量):

class A {
    void methodA(){
        String monitor = "monitor";
        synchronized (monitor){
            //一些代码
        }
    }
}

它们都能正常工作。那么为什么我读到应该避免使用局部变量,因为它们隐式使用池来存储对象?在这种情况下,变量的作用域有什么关系呢?

谢谢!

英文:

There is a lot of material on stack-overflow about synchronization, but I still haven't acquired quality content about deciding which object to use as an intrinsic lock. Can some one actually make a good answer as a rule of thumb?

So should I choose 'monitor' as an instance variable or local variable or instance owning the method? All three of them do the job well. Also primitive value wrapper classes use 'pools' so no problem there as well, as threads 'attack' the same lock.

So why is it better to do this (this):

class A {
    void methodA(){
        synchronized (this){
            //some code    
        }
    }
}

over this(instance variable):

class A {
    String monitor = "monitor";
    void methodA(){
        synchronized (monitor){
            //some code
        }
    }
}

or over this(local variable):

class A {
    void methodA(){
        String monitor = "monitor";
        synchronized (monitor){
            //some code
        }
    }
}

They all work fine/same. So why did I read that I should avoid local variables when they implicitly use pools to store objects? What matter does the scope of variables make in this case?

Thanks!

答案1

得分: 2

你应该避免使用存储在本地变量中的对象的监视器,因为通常只有当前线程可以访问存储在本地变量中的对象。但是在这种特殊情况下,本地变量实际上保存了一个来自常量池的全局共享对象,所以你不会遇到这个特定的问题。

在这里使用常量池对象的监视器存在问题:

String monitor = "monitor";
void methodA() {
    synchronized (monitor){
        //some code
    }
}

问题在于只有一个池化的常量对象。

两个不同的线程操作类A的两个不同实例时,即使你确保它是安全的(例如,你不触及静态共享状态),它们也不能同时进入methodA中的同步块。

更糟糕的是:可能会有其他类B在其他地方,它也碰巧对常量字符串“monitor”进行同步。现在,使用类B的线程将阻塞其他不相关的线程使用类A。

此外,很容易创建死锁,因为你不知不觉地在线程之间共享锁。

英文:

You should avoid using the monitor of objects stored in local variables because typically only the current thread has access to objects stored in local variables. But since in this particular case, the local variable actually holds a globally shared object from the constant pool, you don't suffer from that particular problem.

The problem with using monitors of constant pool objects like here:

String monitor = "monitor";
void methodA() {
    synchronized (monitor){
        //some code
    }
}

... is that there is only one pooled constant object.

Two different threads operating on two different instances of class A cannot enter the synchronized block in methodA at the same time, even if you've ensured it should be safe (for example, you don't touch static shared state).

What's even worse: there might be some other class B somewhere else, which also happens to synchronize on the constant "monitor" string. Now a thread using class B will block other, unrelated, threads from using class A.

On top of that, it's incredibly easy to create a deadlock because you are unknowingly sharing locks between threads.

huangapple
  • 本文由 发表于 2020年8月7日 07:38:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/63293187.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定