您好,我刚刚了解了多线程以及同步在 Java 中的工作原理,所以我尝试对其进行测试。
所以我有这个类(class):
public class testMulti extends Thread{
manageThread obj; //has 2 fields, boolean flag and task name
testMulti(manageThread obj){
this.obj = obj;
}
public void run() {
switch(obj.taskName) {
case "x" :
while(true){
enterQ();
obj.doX() // print "x" and sleep for 5 secs
obj.iBusy = false;
}
case "y" :
while(true){
enterQ();
obj.doX() // print "y" and sleep for 5 secs
obj.iBusy = false;
}
case "z" :
while(true){
enterQ();
obj.doX() // print "z" and sleep for 5 secs
obj.iBusy = false;
}
}
}
synchronized public void enterQ(){
while(true) {
if(!obj.iBusy) {
obj.iBusy = true;
return;
}
}
}
}
我也有这个单独的主程序:
public static void main(String[] args) {
manageThread obj = new manageThread();
obj.taskName = "x";
testMulti test1 = new testMulti(obj);
test2.start();
obj.taskName = "y";
testMulti test2 = new testMulti(obj);
test2.start();
obj.taskName = "z";
testMulti test3 = new testMulti(obj);
test3.start();
}
打印“x”后我有 5 秒的延迟,但“y”和“z”同时出现,我不知道为什么。如果 synchronized 一次只允许 1 个线程,那么 z 是不是应该卡在 enterQ()
中直到 y 完成?
最佳答案
正如@user207421 在他的评论中提到的,您正在使用 testMulti
类的三个独立实例,因此在三个不同的锁上进行同步。参见 synchronized Methods在 JLS 中:
A synchronized method acquires a monitor (§17.1) before it executes.
For a class (static) method, the monitor associated with the Class object for the method's class is used.
最简单(但不是完全正确的修复)是在 testMulti.obj
而不是 enterQ
方法上同步:
public void enterQ(){
synchronized(obj) {
while(true) {
if(!obj.iBusy) {
obj.iBusy = true;
return;
}
}
}
}
这并不完全正确,因为 obj.iBusy = false
是从非同步上下文中调用的,这不能保证其他线程可以看到更改。查看Java Memory Model对于所有血腥的细节。
关于java - 同步方法没有像我预期的那样工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56488131/