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");
}
}
我试图更好地理解java多线程。所以,我知道俗话说只有一个线程可以访问一个对象实例,从而调用该实例的方法(在这种情况下,例如 subtract
类中的 classA
方法。但是,当您仍然拥有
classA
的相同实例时会发生什么? , a
但是两个线程与不同的类 classB
完全想调用a
的方法?我希望消息 out of sync
永远不会被打印出来,但确实如此。毕竟还是只有一个对象实例a
,这是否意味着同步不适用于此示例?
最佳答案
在您的情况下,out of sync
永远不会被打印出来,因为对于您的情况,多线程是正确实现的:执行一系列操作并因此不是原子的关键方法通过使用 synchronized
的行为类似于原子方法。方法的关键字。
假设声明了一个代码块 synchronized (x)
.
第一个进入这个代码块的线程获得对象x
的锁并愉快地执行该代码块。
任何试图进入同一对象上的 block 的非第一个线程x
通过将线程放入 x
的锁池中被“挂起” .一旦当前拥有锁的线程离开 synchronized (x)
block ,来自锁池的随机线程成为执行该 block 的下一个线程。
使用 synchronized
时在实例方法上,它实际上与用 synchronized (this)
包装方法的全部内容相同。 . (对于 static
方法,它将是封闭类的类对象。)
因此,在您的情况下,有一个类的实例 A
,并且所有同步都发生在它上面。
如果你想看out of sync
消息,请尝试删除 synchronized
关键词。一段时间后,您应该会看到预期的 out of sync
信息。
旁注:
out of sync
是一条消息,它可能应该打印在 System.err
,而不是 System.out
. a.rand.nextInt(2) == 1
, 你可以使用 a.rand.nextBoolean()
. class B
访问字段 rand
的 class A
打破封装,你可能想给 class A
一种方法randomBoolean()
return rand.nextBoolean()
, 并调用该方法 randomBoolean()
来自 class B
. class A
, 变量 a
和 b
表示两个数字,在其他情况下,变量 a
和 b
引用 class A
的实例和 class B
.考虑重命名 class A
的字段到别的东西,比如 number1
和 number2
. 关于Java 同步和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63202516/