英文:
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:
-
Lack of proper synchronization: The
synchronized
keyword is used on the methods ofClassA
, but if other parts of your code are not synchronized properly or if there are synchronization issues within therun
method of classB
, it can lead to unsynchronized access toa
. -
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 onSystem.err
, notSystem.out
. - Instead of
a.rand.nextInt(2) == 1
, you could usea.rand.nextBoolean()
. - Having
class B
access fieldrand
ofclass A
breaks encapsulation, you might want to giveclass A
a methodrandomBoolean()
which doesreturn rand.nextBoolean()
, and call that methodrandomBoolean()
fromclass B
. - Having the same variable names with different meanings in different contexts may be confusing. In
class A
, the variablesa
andb
denote two numbers, in other contexts, the variablesa
andb
refer to instances ofclass A
andclass B
. Consider renaming the fields ofclass A
to something else, likenumber1
andnumber2
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论