如果线程没有请求锁定,那么线程是否可以更改java锁定的对象数据?

时间:2016-03-19 19:28:54

标签: java multithreading

Oracle的教程Intrinsic Locks and Synchronization说:

  

内在[监视]锁定在同步的两个方面发挥作用:强制独占访问对象的状态

我假设一个对象中的任何值都不能同时由两个线程操纵,如果一个线程正在执行同步的'方法。

因此,当以下代码具有以下输出时,我感到惊讶(虽然为了我想要的目的而放心)。我不能完全确定会发生什么,但我认为可能会出现错误或某些问题。

根据我的理解,'同步'如果另一个线程正在请求该对象的监视器状态,则仅用于限制对对象的访问 - 但如果该另一个线程正在改变一个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

2 个答案:

答案 0 :(得分:3)

措辞&#34;强制独家访问对象的状态&#34;可能会产生误导。同步代码可用于实现对对象状态的独占访问,但(a)它不强制执行该操作,并且(b)受保护状态不一定是被锁定对象的状态。稍后在该教程中的示例中演示了这一点,其中两个对象lock1lock2用于保护不属于他们的字段c1c2自己的国家。

synchronized强制执行的是代码的独占访问权限 - 同一监视器上synchronized块内的任何代码只能由拥有该监视器的线程运行。这可用于确保对状态的独占访问 - 但前提是您正确编写代码(即,您在synchronized块内放置对该状态的所有访问权限。)

没有什么能阻止您编写从不受保护的代码访问字段的程序,在这种情况下,不会强制执行独占访问。

答案 1 :(得分:0)

让我向您解释一下您的代码发生了什么:

线程t1始终执行locker()方法。

线程t2始终执行adder()方法。

但是,由于locker()是一个同步方法,这意味着它对当前对象持有一个锁,因此线程t2将无法执行

<bean id="SimpleClientHttpRequestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"/>
<bean id="BufferingClientHttpRequestFactory" class="org.springframework.http.client.BufferingClientHttpRequestFactory">
    <constructor-arg ref="SimpleClientHttpRequestFactory"/>
</bean>

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg ref="BufferingClientHttpRequestFactory"/>
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </list>
    </property>
    <property name="interceptors">
        <list>
            <bean class="com.sipl.interceptors.LoggingRequestInterceptor" />
        </list>
    </property>
</bean>

阻塞,直到线程t1完成执行方法锁定。

最终价值: 最后 3 3 仅在t1打印出“LOCKER:3”

之后,由线程t2打印出来

您可能会看到与您发布的输出不同的输出集,如下所示:

synchronized(this){
 ...
}

这是因为线程t2在adder()方法中到达同步块(并获取锁定),之后线程t1可能会获得同步方法锁定器()的锁定。