Java同步和线程

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

Java synchronisation and threads

问题

In this Java multi-threading scenario, you have two threads (t11 and t22) associated with class B that are both trying to call methods of the same instance a of ClassA. Even though the two threads are not associated directly with the object a, they still share access to it because they have a reference to the same ClassA instance.

The synchronization in Java ensures that only one thread can execute synchronized methods of a particular object instance at a time. However, in your case, it seems that the synchronization might not be working as expected, leading to the "Out of sync" message being printed.

There could be a few reasons for this:

  1. Lack of proper synchronization: The synchronized keyword is used on the methods of ClassA, but if other parts of your code are not synchronized properly or if there are synchronization issues within the run method of class B, it can lead to unsynchronized access to a.

  2. External synchronization: If other parts of your code or external factors are modifying the shared state of a, it can also lead to synchronization issues.

To ensure proper synchronization, make sure that all critical sections of code that access and modify shared data (a in this case) are synchronized correctly. Without seeing the complete code and its context, it's challenging to pinpoint the exact issue.

英文:
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. 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.

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? I expected that the message out of sync would never have been printed, but it did. Afterall, there's still only one object instance a, does that imply synchronization doesn't apply in this example?

答案1

得分: 1

在您的情况下,“out of sync”永远不会被打印出来,因为对于您的情况,多线程实现是正确的:执行一系列操作的关键方法并不是原子的,因此通过在方法上使用“synchronized”关键字,使它们像原子方法一样运行。

假设一个代码块声明为“synchronized (x)”。
第一个进入这个代码块的线程获取了对象“x”的锁并愉快地执行了该代码块。

任何尝试在相同对象“x”上进入该块的非第一个线程都会被放置在“x”的“锁池”中而“挂起”。一旦当前持有锁的线程离开“synchronized (x)”块,“锁池”的一个随机线程将成为下一个执行该块的线程。

当在实例方法上使用“synchronized”时,它实际上等效于将方法的整个内容包装在“synchronized (this)”中。(对于“static”方法,它将是封闭类的类对象。)

所以,在您的情况下,有一个“类A”的实例,所有同步都在它上面发生。

如果您想看到“out of sync”消息,请尝试删除“synchronized”关键字。然后,在一段时间后,您应该会看到预期的“out of sync”消息。

附注:

  • 因为“out of sync”是一条消息,它可能应该打印在“System.err”上,而不是“System.out”上。
  • 您可以使用“a.rand.nextBoolean()”来替代“a.rand.nextInt(2) == 1”。
  • 让“类B”访问“类A”的“rand”字段会破坏封装性,您可能希望给“类A”一个方法“randomBoolean()”,它执行“return rand.nextBoolean()”,然后从“类B”调用该方法“randomBoolean()”。
  • 在不同上下文中具有相同变量名称但具有不同含义可能会令人困惑。在“类A”中,变量“a”和“b”表示两个数字,在其他上下文中,变量“a”和“b”分别引用“类A”和“类B”的实例。考虑将“类A”的字段重命名为其他名称,例如“number1”和“number2”。
英文:

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.

Assume a code block is declared synchronized (x).
The first thread that enters this code block obtains the lock of object x and happily executes that code block.

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. 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.

When using synchronized on an instance method, it is effectively the same as wrapping the entire content of the method with synchronized (this). (For static methods, it would be the class object of the enclosing class.)

So, in your case, there is one instance of class A, and all synchronization happens on it.

If you want to see the out of sync message, try removing the synchronized keyword. Then after some time you should see the expected out of sync message.

Sidenotes:

  • Because out of sync is a message, it should probably be printed on System.err, not System.out.
  • Instead of a.rand.nextInt(2) == 1, you could use a.rand.nextBoolean().
  • 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. Consider renaming the fields of class A to something else, like number1 and number2.

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

发表评论

匿名网友

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

确定