简体   繁体   English

java sychronization与对象锁混淆

[英]java sychronization with object lock confusion

I have read many tutorials about Java object level synchronization. 我已经阅读了很多关于Java对象级同步的教程。 And what I understand is whenever a thread is call a synchronized method/block it will acquire a lock on the method's object and release after the execution. 而我所理解的是,每当线程调用同步方法/块时,它将获取方法对象的锁定并在执行后释放。 So no other threads can access the same object data while it is in lock. 因此,在锁定时,没有其他线程可以访问相同的对象数据。 But when I tried the below scenario, found that other thread can access non-synchronized method of a locked object parallel. 但是当我尝试下面的场景时,发现其他线程可以访问并行锁定对象的非同步方法。

class A {
    public synchronized void test1(){}
    public void test2(){}
}  

I created 3 threads t1 , t2 and t3 . 我创建了3个线程t1t2t3 And all are referring the same object of class A. t1 is calling test1() and other two threads calling test2() . 并且所有都引用了类A的相同对象.t1正在调用test1()和其他两个调用test2()线程。 Here I can see that while test1() is executing, t2 and t3 threads test2() also running in parallel. 在这里我可以看到,当test1()正在执行时, t2t3线程test2()也并行运行。

So my question is does the synchronization really locks an object completely or it just lock only the particular synchronized method? 所以我的问题是同步是否真的完全锁定了一个对象,或者它只锁定了特定的同步方法? If so why it is calling as object level locking. 如果是这样,为什么它调用对象级锁定。

What will happen in the case of class level locking? 在类级别锁定的情况下会发生什么?

Synchronization ensures that any thread that needs to execute a block of code in a synchronized block will first have to get the Object's monitor ( lock ) before the execution of code inside the block starts. 同步确保任何需要在同步块中执行代码块的线程首先必须在块内部的代码执行开始之前获取Object的监视器( 锁定 )。 Thus when one thread is executing code inside a synchronized block, other threads that try to execute the same or other synchronized blocks (on the same object ie same lock ) will have to wait until they get the lock. 因此,当一个线程在同步块内执行代码时,尝试执行相同或其他同步块的其他线程(在同一对象上,即相同的 )将不得不等到它们获得锁定。

Other threads are allowed to execute code in code blocks that are not synchronized because that doesn't involve acquiring the monitor / lock. 允许其他线程在未同步的代码块中执行代码,因为这不涉及获取监视器/锁定。 Note that other threads can even execute code that is in synchronized blocks if they need to acquire a different lock. 请注意,如果需要获取不同的锁,其他线程甚至可以执行同步块中的代码。

Other threads will need to acquire lock if they try to execute any other method which is synchronised. 如果其他线程尝试执行任何其他已同步的方法,则需要获取锁定。 They are free to call other method which do not have synchronised keyword (even if the lock is aquired by some thread) as to call them they do not need to aquire lock / moniter. 他们可以自由地调用其他没有synchronized关键字的方法(即使锁被一些线程获取),因为调用它们不需要获取lock / moniter。

There's a different between explicitly locking to an object (eg an instance of A ), and the intrinsic locking idioms declared in your A class. 显式锁定对象(例如A的实例)与A类中声明的内部锁定习语之间存在差异。

In your case, method test1 is instance-synchronized, which means that for a given instance of A , only one thread at the time can invoke it. 在您的情况下,方法test1是实例同步的,这意味着对于给定的A实例,当时只有一个线程可以调用它。

However, test2 is not synchronized, therefore any thread at any given time can invoke it in theory. 但是, test2不同步,因此任何给定时间的任何线程都可以在理论上调用它。

Now if you synchronized(myAInstance) , then once the lock is acquired, only the executing code within the synchronized statement will be able to invoke any method of your A instance, until the lock is released. 现在,如果您synchronized(myAInstance) ,那么一旦获得锁定,只有synchronized语句中的执行代码才能调用A实例的任何方法,直到锁定被释放。

You are really mixing up things. 你真的搞混了什么。

class A {
  public synchronized void test1(){}
  public void test2(){}
}  

This creates a synchronized access to your test1 method. 这将创建对test1方法的同步访问。 This means, that only one thread in parallel could execute that method. 这意味着,只有一个并行线程可以执行该方法。 If you want to have a lock accross methods you could create your own lock object: 如果你想拥有一个锁定方法,你可以创建自己的锁对象:

class A {
   private static final Object myLock= new Object();

   public void test1(){
      synchronized (myLock){

      }
   }
   public void test2(){
      synchronized (myLock){

      }
   }
}  

If any other person in your application uses the same object, your thread is blocked, too. 如果应用程序中的任何其他人使用相同的对象,则您的线程也会被阻止。 Normally you define some kind of lock object structure that everybody follows. 通常你定义一种每个人都遵循的锁对象结构。

While thinking of synchronization as a means for exclusion might be appropriate in many cases, there is another way to think of it that might be more illustrative for others, and that is the idea of visibility . 虽然在许多情况下将同步视为排除手段可能是合适的,但还有另一种方法可以将其视为对其他人更具说明性,这就是可见性的概念。

Exiting a synchronized block means that all of your changes are committed back to memory. 退出同步块意味着所有更改都将提交回内存。 Entering a synchronized block guarantees that all changes anyone else might have done to the memory you are about to access are properly visible to you. 输入同步块可确保您可以正确地看到其他人可能对您要访问的内存所做的所有更改。

If you think of synchronization as a way to lock others out while you are doing your stuff, you need to think of it as an "occupied"-note rather than a door lock: it is only by the others courtesy you can be alone - that is, if they, too, are using the same synchronization mechanism. 如果你认为同步是一种在你做东西的时候锁定别人的方法,你需要把它想象成一个“被占用” - 而不是门锁:只有其他人礼貌你才能独自一人 - 也就是说,如果他们也使用相同的同步机制。 Thinking about visibility makes it easier to grasp why it pays off to be courteous. 考虑可见性使得更容易理解为什么有礼貌才能得到回报。

In your case, of course, both the test1 and the test2 methods have to me marked 'synchronized'. 当然,在你的情况下, test1test2方法都必须标记为'synchronized'。 This is the same as using the A-object as a lock. 这与将A对象用作锁定相同。

Going further, I would really like to encourage you to have a look at the java.util.concurrent -package and its subpackages atomic and locks . 更进一步,我真的很想鼓励你看一下java.util.concurrent -package及其子包atomiclocks Most of the things you want to achieve is already implemented there, and using the libraries makes things easier and safer for you. 您想要实现的大部分内容已经在那里实现,使用这些库可以让您更轻松,更安全。 It also makes your code more maintainable and easier to read. 它还使您的代码更易于维护和更易于阅读。

Read oracle documentation page on synchrnoized methods 阅读有关同步方法的 oracle文档页面

Making these methods synchronized has two effects: 使这些方法synchronized有两个影响:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. 首先,对同一对象的两个synchronized方法的调用不可能进行交错。 When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. 当一个线程正在为对象执行synchronized方法时,所有其他线程调用同一对象的synchronized方法(暂停执行)直到第一个线程完成对象。

=> At any point of time, you can't execute two synchronized methods on same object in parallel. =>在任何时候,您都不能并行地在同一对象上执行两个synchronized方法。

Coming back to your query: 回到您的查询:

test1() is synchronized and test2() is not. test1()synchronizedtest2()不是。

T1 execution of test1() and T2 & T3 exection of test2() does not break above rule and hence they can run in parallel. T1 execution of test1() and T2 & T3 exection of test2() does not break above rule ,因此它们可以并行运行。

If you change test2() to synchronized method, things will change. 如果将test2()更改为synchronized方法,事情就会发生变化。

In this case, till T1 completes it's execution of test1() , T2 and T3 have to wait till T1 completes it's execution. 在这种情况下,直到T1完成它的执行test1()T2 and T3必须等到T1完成它的执行。 Once T1 completes its execution, then one of T2 or T3 can invoke test2() method. 一旦T1完成执行, T2 or T3可以调用test2()方法。

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

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