[英]Can a thread change java locked object data if it is not requesting the lock itself?
Oracle的Intrinsic Locks and Synchronization教程说:
内在[Monitor]锁在同步的两个方面都起作用:强制独占访问对象的状态
我假设如果一个线程正在执行“同步”方法,则一个对象中的值不会被两个线程同时操纵。
因此,当以下代码具有以下输出时,我感到惊讶(虽然为了我想要的目的而放心)。 我不完全确定会发生什么,但我认为可能会出现错误或某些问题。
根据我的理解,'synchronized'仅限于限制对象的访问,如果另一个线程正在请求该对象的监视器状态 - 但是如果该另一个线程正在改变一个off值,则不会。 它是否正确?
public class HelloWorld implements Runnable{
Thread t1;
Thread t2;
int val1 = 0;
int val2 = 0;
public static void main(String[] args) {
HelloWorld h1 = new HelloWorld();
h1.t1 = new Thread(h1);
h1.t2 = new Thread(h1);
h1.t1.start();
h1.t2.start();
}
@Override
public void run() {
System.out.println("STARTED");
System.gc();
Thread currentThread = Thread.currentThread();
if (currentThread == this.t1) {
this.locker(); //This is a synchronized method, incrementing val1
}
if (currentThread == this.t2) {
this.adder(); //This is a non-synchronized method, incrementing val2
}
}
private synchronized void locker() {
for(int i = 0; i < 3; i++){
val1++;
System.out.println("LOCKER: " + this.val1);
}
}
private void adder() {
while(this.val2 < 3) {
this.val2++;
System.out.println("ADDER: " + this.val2);
}
synchronized(this) {
//Synchronize for final output
System.out.println("FINAL");
System.out.println(val1);
System.out.println(val2);
}
}
}
STARTED
STARTED
ADDER: 1
LOCKER: 1
LOCKER: 2
ADDER: 2
LOCKER: 3
ADDER: 3
FINAL
3
3
措辞“强制独占访问对象的状态”可能会产生误导。 同步代码可用于实现对对象状态的独占访问,但(a)它不强制执行,并且(b)受保护状态不一定是被锁定对象的状态。 稍后在该教程中的示例中演示了这一点,其中两个对象lock1
和lock2
用于保护不属于其自身状态的字段c1
和c2
。
synchronized
强制执行的是对代码的独占访问 - 同一监视器上synchronized
块内的任何代码只能由拥有该监视器的线程运行。 这可用于确保对状态的独占访问 - 但前提是您正确编写代码(即将所有访问权限置于synchronized
块中)。
没有什么能阻止您编写从不受保护的代码访问字段的程序,在这种情况下,不会强制执行独占访问。
让我向您解释一下您的代码发生了什么:
线程t1始终执行locker()方法。
线程t2始终执行adder()方法。
但是,由于locker()是一个同步方法,这意味着它保持对当前对象的锁定,因此线程t2将无法执行
synchronized(this){
...
}
阻止,直到线程t1完成执行方法锁定。
最终值:FINAL 3 3由线程t2打印出来,仅在t1打印出“LOCKER:3”之后
您可能会看到与您发布的输出不同的输出集,如下所示:
STARTED
STARTED
ADDER: 1
ADDER: 2
ADDER: 3
FINAL
0
3
LOCKER: 1
LOCKER: 2
LOCKER: 3
这是因为线程t2在adder()方法中到达同步块(并获取锁定),之后线程t1可以获取同步方法锁定器()的锁定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.