简体   繁体   English

Java 同步和线程

[英]Java synchronisation and threads

import java.util.Random;

public class ClassA{
  int a = 0, b = 10;
  Random rand = new Random();

  public synchronized void add(){
      if (a < 10){ 
         a++;
         b--;
      };
  }

  public synchronized void subtract(){
      if (b < 10){ 
         b++;
         a--;
      }
  }
  
  public synchronized boolean check(){
     return a + b == 10;
  }
  
  
  public static void main(String args[]){
      
      ClassA a = new ClassA();
      
      B ba = new B(a);
      B bb = new B(a);
      
       //notice these two threads are not associated with the object a!
      Thread t11 = new Thread(bb);
      Thread t22 = new Thread(ba);
      t11.start(); 
      t22.start();
  }
}


class B implements Runnable{
    ClassA a;
    
    B(ClassA a){
        this.a = a;
    }
   
    @Override
    public void run(){
        while (a.check()){
          if (a.rand.nextInt(2) == 1)
              a.subtract();
          else
              a.add();
      } System.out.print("Out of sync");
    }
}

I'm trying to understand java multi-threading better.我试图更好地理解 java 多线程。 So, I know that the saying goes only one thread can access an object instance and thus call that instance's method (in this case for example, the subtract method in class classA .所以,我知道俗话说只有一个线程可以访问 object 实例,从而调用该实例的方法(在这种情况下,例如 class classA中的subtract方法。

But what happens when, you still have the same instance of classA , a but two threads associated with a different class classB altogether trying to call a 's methods?但是,当您仍然有相同的classA实例,但a两个线程与不同a class classB关联时,会发生什么情况? I expected that the message out of sync would never have been printed, but it did.我希望永远不会打印不out of sync的消息,但确实如此。 Afterall, there's still only one object instance a , does that imply synchronization doesn't apply in this example?毕竟,仍然只有一个 object 实例a ,这是否意味着同步不适用于此示例?

In your case, out of sync would never be printed, because for your situation, the multithreading is implemented correctly: The critical methods that perform a sequence of operations and are thus not atomic are made behave like atomic methods by the using the synchronized keyword on the method.在您的情况下,永远不会打印不out of sync ,因为对于您的情况,正确实现了多线程:执行一系列操作并因此不是原子的关键方法通过使用synchronized关键字 on方法。

Assume a code block is declared synchronized (x) .假设一个代码块被声明为synchronized (x) The first thread that enters this code block obtains the lock of object x and happily executes that code block.进入该代码块的第一个线程获得了 object x的锁并愉快地执行该代码块。

Any non-first thread that tries to enter the block on the same object x is "suspended" by putting the thread in the lock pool of x .任何试图进入同一个 object x块的非第一个线程都会通过将线程放入x锁池中来“暂停”。 As soon as the thread that currently has the lock leaves the synchronized (x) block, a random thread from the lock pool becomes the next thread to execute that block.一旦当前拥有锁的线程离开synchronized (x)块,锁池中的一个随机线程将成为下一个执行该块的线程。

When using synchronized on an instance method, it is effectively the same as wrapping the entire content of the method with synchronized (this) .在实例方法上使用synchronized时,它实际上与使用synchronized (this)包装方法的全部内容相同。 (For static methods, it would be the class object of the enclosing class.) (对于static方法,它将是封闭 ZA2F2ED4F8EBC2CBB16C21A29DC40 的 class object)。

So, in your case, there is one instance of class A , and all synchronization happens on it.因此,在您的情况下,有一个 class A实例,所有同步都发生在它上面。

If you want to see the out of sync message, try removing the synchronized keyword.如果您想查看out of sync消息,请尝试删除synchronized关键字。 Then after some time you should see the expected out of sync message.一段时间后,您应该会看到预期out of sync消息。

Sidenotes:旁注:

  • Because out of sync is a message, it should probably be printed on System.err , not System.out .因为out of sync是一条消息,它可能应该打印在System.err上,而不是System.out上。
  • Instead of a.rand.nextInt(2) == 1 , you could use a.rand.nextBoolean() .您可以使用a.rand.nextBoolean()而不是a.rand.nextInt(2) == 1
  • Having class B access field rand of class A breaks encapsulation, you might want to give class A a method randomBoolean() which does return rand.nextBoolean() , and call that method randomBoolean() from class B . Having class B access field rand of class A breaks encapsulation, you might want to give class A a method randomBoolean() which does return rand.nextBoolean() , and call that method randomBoolean() from class B .
  • Having the same variable names with different meanings in different contexts may be confusing.在不同的上下文中具有不同含义的相同变量名可能会令人困惑。 In class A , the variables a and b denote two numbers, in other contexts, the variables a and b refer to instances of class A and class B .class A中,变量ab表示两个数字,在其他上下文中,变量ab指的是class Aclass B的实例。 Consider renaming the fields of class A to something else, like number1 and number2 .考虑将class A的字段重命名为其他名称,例如number1number2

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

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