简体   繁体   English

synchronized(this)是否仅锁定同步块或所有“this”代码?

[英]Does synchronized (this) lock only the synchronized block or all the “this” code?

public class ObjectCounter {
    private static long numOfInstances = 0;
    public ObjectCounter(){
        synchronized(this){
        numOfInstances++;
        }
    }
    **public static synchronized long getCount(){
        return numOfInstances;
    }**
//vs//
    **public static long getCount(){
        return numOfInstances;
    }**
}

if I'll run few threads, some of them call the static function getCount() and some of them create new instances. 如果我将运行少量线程,其中一些调用静态函数getCount() ,其中一些创建新实例。 I want to get in each call to getCount() the real number of instances at the time. 我希望每次调用getCount()获得实际的实例数。

  1. Is there a difference between the two options in the code? 代码中的两个选项有区别吗?
  2. If I lock " this " shouldn't it mean that I can't call getCount() until the constructor exits the synchronized block (lets say if I don't write synchronize on the getCount()). 如果我锁定“ this ”不应该意味着我不能调用getCount()直到构造函数退出synchronized块(假设我没有在getCount()上写同步)。
  3. if I do a synchronized block in some place in the code, does it lock only the synchronized block or all the " this " code? 如果我在代码中的某个地方执行同步块,它是仅锁定同步块还是所有“ this ”代码?
  4. From here down EDIT: thank you all, it was very helpful, but I have a few more questions following your answers. 从这里开始编辑:谢谢大家,这非常有帮助,但我还有一些问题可以回答你的问题。
  5. If I understand correctly, the synchronized(this) block doesn't effect (or connected to) the static synchronized function (in lock terms not the numOfInstances increment)? 如果我理解正确,synchronized(this)块不会影响(或连接到)静态同步函数(以锁定术语而不是numOfInstances增量)?
  6. is there a better option to make the increment and the getCount() function Thread-safe? 是否有更好的选项来使增量和getCount()函数线程安全? (like open a static object and do synchronized(obj) instead synchronized(this) - friend suggested). (比如打开一个静态对象并执行synchronized(obj)而不是synchronized(this) - 朋友建议)。
  7. If I had a f1() method (non-static) in ObjectCounter class, while one thread is in the synchronized(this) can other thread enter f1() block (not a synchronized class or have synchronized block inside)? 如果我在ObjectCounter类中有一个f1()方法(非静态),而一个线程在同步(this)中,其他线程可以输入f1()块(不是同步类或者里面有同步块)?
  8. If I had a f1() method (non-static) and f2() method (non-static) in ObjectCounter, in f1() I have synchronized(this) block. 如果我在ObjectCounter中有一个f1()方法(非静态)和f2()方法(非静态),在f1()中我有同步(this)块。 while one thread is in the synchronized(this) block, can other thread enter f1() block (not a synchronized class or have synchronized block inside)? 当一个线程在同步(this)块中时,其他线程是否可以进入f1()块(不是同步类或内部有同步块)? (lets say both of the threads "working" on the same instance) (假设两个线程在同一个实例上“工作”)

` `

Using synchronized means in order for a thread to execute that block or method, it has to acquire a lock referenced (explicitly or implicitly) by that block or method. 使用synchronized手段以使线程执行该块或方法,它必须获取该块或方法引用(显式或隐式)引用的锁。 For the static synchronized methods, that lock is the monitor on the class object. 对于static synchronized方法,该锁定是类对象上的监视器。 For the synchronized(this) block, the lock used is the monitor on the current instance. 对于synchronized(this)块,使用的锁是当前实例上的监视器。 Sharing of locks between multiple methods or blocks is what enforces atomicity and memory visibility of updates, also the shared lock provides a shared communication path through which waiting and notification can take place. 在多个方法或块之间共享锁是强制更新的原子性和内存可见性的,共享锁还提供了共享通信路径,通过该路径可以进行等待和通知。

Since the static synchronized blocks use a different lock from that used by the block in the constructor, entering a static synchronized block is not blocked by another thread's accessing the block that requires acquiring the lock on the current instance, and the synchronized block in the constructor has no effect on anything, the lock acquisition will always be uncontended. 由于静态同步块使用与构造函数中的块使用的锁不同的锁,因此进入静态同步块不会被另一个线程访问需要获取当前实例上的锁的块以及构造函数中的synchronized块阻止对任何事情都没有影响,锁定获取将永远是无竞争的。 More importantly here, changes made by one thread in the constructor may not get seen by other threads using the getter. 更重要的是,这里使用getter的其他线程可能无法看到构造函数中的一个线程所做的更改。 Synchronization affects both locking and memory visibility. 同步会影响锁定和内存可见性。

This changed version would work: 这个改变版本可行:

public class ObjectCounter {
    private static long numOfInstances = 0;
    public ObjectCounter(){
        synchronized(ObjectCounter.class){
            numOfInstances++;
        }
    }
    public static synchronized long getCount(){
        return numOfInstances;
    }
}

because the getter and the incrementing block are using the same lock. 因为getter和递增块使用相同的锁。 Making the different threads acquire the same monitor ensures that the change to the counter gets safely published so that another thread accessing the getter can see the updated value. 使不同的线程获得相同的监视器可确保对计数器的更改安全地发布,以便访问getter的另一个线程可以看到更新的值。

The synchronized keyword says, "you have to acquire a lock before you can enter", where for the method the lock is assumed: with the static keyword on the method it's the monitor on the class, without a static keyword it's the monitor on the current instance. synchronized关键字表示“你必须在输入之前获得一个锁”,假设锁的方法在哪里:方法上的static关键字是类的监视器,没有静态关键字,它是监视器上的当前实例。 For locking to work correctly the different blocks and methods need to use the same lock. 为了使锁定正常工作,不同的块和方法需要使用相同的锁。 There is arguably too much syntax sugar and too much making things convenient in how Java was designed: allowing implicit choice of locks and putting the monitor on java.lang.Object can cause confusion. 可以说有太多的语法糖和太多使得Java的设计方便:允许隐式选择锁并将监视器放在java.lang.Object上会引起混淆。

WRT your question #6: For what you're doing here you'd be better off with an AtomicLong . 写下您的问题#6:对于您在这里所做的事情,您最好使用AtomicLong Use synchronized blocks for coordinating multiple changes that need to take place without interference from other threads. 使用synchronized块来协调需要进行的多个更改,而不会受到其他线程的干扰。

Questions #3, #7 and #8 seem very similar: If a method/block isn't attempting to acquire a lock, nothing prevents threads from executing that method/block. 问题#3,#7和#8看起来非常相似:如果方法/块没有尝试获取锁,则没有什么能阻止线程执行该方法/块。 The object as a whole doesn't get any protection, using the synchronized methods or blocks to enforce locking is what does the protecting. 对象作为一个整体没有得到任何保护,使用同步方法或块来强制执行锁定是什么保护。 Think less in terms of "using the synchronized keyword" and more in terms of what lock threads need to acquire. 在“使用synchronized关键字”方面少考虑一下,在锁线程需要获取的内容方面更多。

  1. Yes there is a difference in the options. 是的,选项有所不同。 In the above option, two threads cannot call getCount() at the same time, in the below one they can. 在上面的选项中,两个线程不能同时调用getCount() ,在下面的一个线程中它们可以。

  2. Yes, that is correct. 对,那是正确的。 There can only be one thread at the same time holding a lock on an object. 只能有一个线程同时锁定一个对象。

  3. Each object has its own lock. 每个对象都有自己的锁。 So it lock all synchronized (this) block of that object. 因此它锁定该对象的所有synchronized (this)块。

Note, however, that each object has a lock of its own and also each class has a lock of its own. 但请注意,每个对象都有自己的锁,并且每个类都有自己的锁。 In the constructor you use the object lock to access a static (class) variable, while in getCount() you use the class lock. 在构造函数中,您使用对象锁来访问静态(类)变量,而在getCount()使用类锁。 That means that your code is not thread-safe! 这意味着您的代码不是线程安全的!

synchronized steps: synchronized步骤:

  1. Check if object lock is already acquired. 检查是否已获取对象锁定。 If so, proceed into synchronized block/method 如果是,请继续进入synchronized块/方法
  2. Attempt to aquire lock. 试图获得锁定。 If the lock has already been acquired by another thread, then the thread will wait for the lock to be released, at which point it will go through the cycle (2.) again 如果锁已被另一个线程获取,则线程将等待锁被释放,此时它将再次经历循环(2.)

Is there a difference between the two options in the code? 代码中的两个选项有区别吗?

Yes, there is clear difference. 是的,有明显的区别。 In first, you are synchronizing threads access to getCount() method on the class object of ObjectCounter . 首先,您正在同步对ObjectCounter的类对象的getCount()方法的线程访问。 While in second you are not. 而在第二,你不是。

If I lock "this" shouldn't it means that I can't call getCount() until the contractor exit the synchronized block (lets say if I don't write synchronize on the getCount()). 如果我锁定“this”不应该意味着我不能调用getCount()直到承包商退出synchronized块(假设我没有在getCount()上写同步)。

Since there is only one lock of an object (class locks are different which are held through using static keyword along with synchronized ), so if some other thread is acquiring that lock either because of synchronized(this){ or because of this synchronized long getCount(){ then the new thread trying to acquire the lock has to wait until the previous thread has released the lock. 由于对象只有一个锁(类锁是不同的,通过使用static关键字和synchronized ),所以如果其他一些线程由于synchronized(this){或者因为这个synchronized long getCount(){而获取该锁定synchronized long getCount(){然后尝试获取锁的新线程必须等到前一个线程释放锁。

Now since in your case, you are doing, static synchronized long getCount(){ , so, its locking becomes different from synchronized(this){ . 现在,在你的情况下,你正在做, static synchronized long getCount(){ ,因此,它的锁定与synchronized(this){ Which means that if some thread is acquiring a lock because of synchronized(this){ and some other thread is trying to invoke getCount() then that thread will not be blocked. 这意味着如果某个线程由于synchronized(this){并且其他一些线程试图调用getCount()而获取锁定,那么该线程将不会被阻塞。

if I do a synchronized block in some place in the code, does it locks the only the synchronized block or all the "this" code? 如果我在代码中的某个地方执行同步块,它是否仅锁定同步块或所有“此”代码?

  1. Non-static synchronization: If you do synchronized block in some place in the code and it is non-static public synchronized long getCount(){ , then also the lock of your object will be held, so new thread trying to acquire the lock has to wait until the previous thread has released the lock. 非静态同步:如果你在代码中的某个地方执行同步块并且它是非静态的public synchronized long getCount(){ ,那么你的对象的锁也会被保存,所以新线程试图获取锁具有等到上一个线程释放锁定。

  2. Static synchronization: If you do synchronized block in some place in the code and it is static public static synchronized long getCount(){ , then it will have no effect on lock of non-static sychronization. 静态同步:如果你在代码中的某个地方进行了同步块,那么它是静态的public static synchronized long getCount(){ ,那么它对锁定非静态同步没有影响。


Bottom line: 底线:

  • There is only and only one lock for one object , and if that lock is acquired by some thread then other threads has to wait until that lock released. 一个对象只有一个锁定 ,如果某个线程获取该锁定,则其他线程必须等待该锁定释放。

  • Then there is a class lock, which is held if static keyword is used along with synchronized keyword. 然后有一个类锁,如果static关键字与synchronized关键字一起使用,则会保持该类锁。

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

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