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

Ori*_*avi 4 java multithreading synchronized synchronized-block java-threads

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;
    }**
}
Run Code Online (Sandbox Code Playgroud)

如果我运行少量线程,其中一些调用静态函数getCount(),其中一些创建新实例.我希望每次调用getCount()实际数量的实例.

  1. 代码中的两个选项有区别吗?
  2. 如果我锁定" this"不应该意味着我不能调用,getCount()直到构造函数退出synchronized块(假设我没有在getCount()上写同步).
  3. 如果我在代码中的某个地方执行同步块,它是仅锁定同步块还是所有" this"代码?
  4. 从这里开始编辑:谢谢大家,这非常有帮助,但我还有一些问题可以回答你的问题.
  5. 如果我理解正确,synchronized(this)块不会影响(或连接到)静态同步函数(以锁定术语而不是numOfInstances增量)?
  6. 是否有更好的选项来使增量和getCount()函数线程安全?(比如打开一个静态对象并执行synchronized(obj)而不是synchronized(this) - 朋友建议).
  7. 如果我在ObjectCounter类中有一个f1()方法(非静态),而一个线程在同步(this)中,其他线程可以输入f1()块(不是同步类或者里面有同步块)?
  8. 如果我在ObjectCounter中有一个f1()方法(非静态)和f2()方法(非静态),在f1()中我有同步(this)块.当一个线程在同步(this)块中时,其他线程是否可以进入f1()块(不是同步类或内部有同步块)?(假设两个线程在同一个实例上"工作")

`

Nat*_*hes 9

使用synchronized手段以使线程执行该块或方法,它必须获取该块或方法引用(显式或隐式)引用的锁.对于static synchronized方法,该锁定是类对象上的监视器.对于synchronized(this)块,使用的锁是当前实例上的监视器.在多个方法或块之间共享锁是强制更新的原子性和内存可见性的,共享锁还提供了共享通信路径,通过该路径可以进行等待和通知.

由于静态同步块使用与构造函数中的块使用的锁不同的锁,因此进入静态同步块不会被另一个线程访问需要获取当前实例上的锁的块以及构造函数中的synchronized块阻止对任何事情都没有影响,锁定获取将永远是无竞争的.更重要的是,这里使用getter的其他线程可能无法看到构造函数中的一个线程所做的更改.同步会影响锁定和内存可见性.

这个改变版本可行:

public class ObjectCounter {
    private static long numOfInstances = 0;
    public ObjectCounter(){
        synchronized(ObjectCounter.class){
            numOfInstances++;
        }
    }
    public static synchronized long getCount(){
        return numOfInstances;
    }
}
Run Code Online (Sandbox Code Playgroud)

因为getter和递增块使用相同的锁.使不同的线程获得相同的监视器可确保对计数器的更改安全地发布,以便访问getter的另一个线程可以看到更新的值.

synchronized关键字表示"你必须在输入之前获得一个锁",假设锁的方法在哪里:方法上的static关键字是类的监视器,没有静态关键字,它是监视器上的当前实例.为了使锁定正常工作,不同的块和方法需要使用相同的锁.可以说有太多的语法糖和太多使得Java的设计方便:允许隐式选择锁并将监视器放在java.lang.Object上会引起混淆.

写下您的问题#6:对于您在这里所做的事情,您最好使用AtomicLong.使用synchronized块来协调需要进行的多个更改,而不会受到其他线程的干扰.

问题#3,#7和#8看起来非常相似:如果方法/块没有尝试获取锁,则没有什么能阻止线程执行该方法/块.对象作为一个整体没有得到任何保护,使用同步方法或块来强制执行锁定是什么保护.在"使用synchronized关键字" 方面少考虑一下,更多地考虑锁线程需要获取的内容.

  • 坏狗!Noobs需要了解锁与块无关,与方法无关,与变量无关.我已经失去了多少次我见过他们的问题,"两个线程怎么可能同时进入同一个同步的块/方法呢?" 或者,"两个线程如何同时在`count`上同步?" 他们需要非常清楚地说明,"synchronized"唯一阻止的是两个线程同时锁定同一个_instance_. (2认同)