简体   繁体   English

一个线程是否可以更改java锁定的对象数据,如果它没有请求锁本身?

[英]Can a thread change java locked object data if it is not requesting the lock itself?

Oracle's tutorial Intrinsic Locks and Synchronization says: Oracle的Intrinsic Locks and Synchronization教程说:

Intrinsic[Monitor] locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state 内在[Monitor]锁在同步的两个方面都起作用:强制独占访问对象的状态

I assumed no value in an object could be manipulated by two threads at once, should one thread be executing a 'synchronized' method. 我假设如果一个线程正在执行“同步”方法,则一个对象中的值不会被两个线程同时操纵。

As such, I was surprised (although relieved for the purposes of what I am looking to do) when the following code had the following output. 因此,当以下代码具有以下输出时,我感到惊讶(虽然为了我想要的目的而放心)。 I wasn't entirely sure what to expect, however I figured an error or some point might occur. 我不完全确定会发生什么,但我认为可能会出现错误或某些问题。

From what I can understand, 'synchronized' merely acts to restrict access to an object, if another thread is requesting the monitor state for that object -- but not if that other thread is altering a one off value. 根据我的理解,'synchronized'仅限于限制对象的访问,如果另一个线程正在请求该对象的监视器状态 - 但是如果该另一个线程正在改变一个off值,则不会。 Is this correct? 它是否正确?

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

The phrasing "enforcing exclusive access to an object's state" may be misleading. 措辞“强制独占访问对象的状态”可能会产生误导。 Synchronized code can be used to achieve exclusive access to an object's state, but (a) it doesn't enforce that, and (b) the protected state is not necessarily the state of the object that is being locked. 同步代码可用于实现对对象状态的独占访问,但(a)它不强制执行,并且(b)受保护状态不一定是被锁定对象的状态。 This is demonstrated in the example later on in that tutorial, where the two objects lock1 and lock2 are used to protect the fields c1 and c2 which are not part of their own state. 稍后在该教程中的示例中演示了这一点,其中两个对象lock1lock2用于保护不属于其自身状态的字段c1c2

What synchronized enforces is exclusive access to code - any code that is within a synchronized block on the same monitor can be ran only by the thread that owns that monitor. synchronized强制执行的是对代码的独占访问 - 同一监视器上synchronized块内的任何代码只能由拥有该监视器的线程运行。 This can be used to ensure exclusive access to the state - but only if you write your code properly (ie you place all access to that state within synchronized blocks). 这可用于确保对状态的独占访问 - 但前提是您正确编写代码(即将所有访问权限置于synchronized块中)。

Nothing prevents you from writing a program that accesses a field from unprotected code, and in that case, exclusive access will not be enforced. 没有什么能阻止您编写从不受保护的代码访问字段的程序,在这种情况下,不会强制执行独占访问。

Let me explain to you what is happening to your code: 让我向您解释一下您的代码发生了什么:

Thread t1 always executes the locker() method. 线程t1始终执行locker()方法。

Thread t2 always executed the adder() method. 线程t2始终执行adder()方法。

But, since locker() is a synchronized method, that means it holds a lock on the current object, therefore thread t2 will not be able to execute the 但是,由于locker()是一个同步方法,这意味着它保持对当前对象的锁定,因此线程t2将无法执行

synchronized(this){
 ...
}

block until thread t1 finishes executing method locker. 阻止,直到线程t1完成执行方法锁定。

The final value: FINAL 3 3 is printed out by Thread t2, only after t1 prints out "LOCKER: 3" 最终值:FINAL 3 3由线程t2打印出来,仅在t1打印出“LOCKER:3”之后

You might see a different set of output than the one you have posted, like the following: 您可能会看到与您发布的输出不同的输出集,如下所示:

STARTED
STARTED
ADDER: 1
ADDER: 2
ADDER: 3
FINAL
0
3
LOCKER: 1
LOCKER: 2
LOCKER: 3

This is because Thread t2 reaching the synchronized block(and acquiring lock) in adder() method, before thread t1 could ever acquire lock for synchronized method locker(). 这是因为线程t2在adder()方法中到达同步块(并获取锁定),之后线程t1可以获取同步方法锁定器()的锁定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM