21

Java中的监视器是否不限制对实例变量的访问,而仅限于声明为同步的方法或同步语句中的代码?

我创建了两个线程,thread y调用sync()方法,该方法声明为同步,而thread r调用unsync()未声明为同步的方法。两者都调用共享对象上的方法s

Thread r能够修改对象的实例变量,s而该对象的监视器仍由thread y.

是不是 Java 中的监视器不限制对实例变量的访问,而仅限于声明为同步的方法或同步语句中的代码?

public class Stuff {

    private int a = 10;

    public synchronized void sync() {
        long t1 = System.currentTimeMillis();
        System.out.println("Okay, I am in sync() method. "
                        + "I will be waiting for 10 seconds. Current Time = "
                        + System.currentTimeMillis());
        while (System.currentTimeMillis() - t1 < 10000);
        System.out.println("Okay, I have waited for 10 seconds. Current time is "
                        + System.currentTimeMillis()
                        + ". Now I will exit from sync() method, a = " + this.a);
    }

    public void unsync() {
        System.out.println("Alright, I am in unsync() method. The current time is "
                        + System.currentTimeMillis());
        this.a = this.a + 1;
        System.out.println(". The time of exit from unsync() method is "
                        + System.currentTimeMillis());

    }
}

class T1 extends Thread {

    Stuff s;

    public T1(Stuff s) {
        this.s = s;
    }

    public void run() {
        s.sync();
    }
}

class T2 extends Thread {

    Stuff s;

    public T2(Stuff s) {
        this.s = s;
    }

    public void run() {
        s.unsync();
    }
}

class Main {

    public static void main(String args[]) throws Exception {
        Stuff s = new Stuff();
        T1 y = new T1(s);
        T2 r = new T2(s);
        y.start();
        Thread.sleep(2000);
        r.start();
    }
}

程序的输出如下:

 
好的,我在 sync() 方法中。我将等待 10 秒。当前时间 = 1358801766310  
好吧,我在 unsync() 方法中。当前时间为1358801768343。退出unsync()方法的时间为1358801768343  
好的,我已经等了 10 秒。当前时间是 1358801776310。现在我将退出 sync() 方法,a = 11
4

3 回答 3

18

是的。持有一个对象的监视器可以防止另一个线程执行另一个代码块或在同一个对象上同步。如果一个方法没有同步,任何线程都可以随时调用它,而不管另一个线程是否持有监视器。

如果至少有一个线程有可能修改此共享状态,则对共享状态的每次访问,即使是只读访问,都必须同步。

于 2013-01-21T21:02:09.843 回答
3

java中的监视器是否不限制对实例变量的访问,而仅限于声明为同步的方法或同步语句中的代码?

是的。

除其他外,同步块(或方法)是互斥的。这不会阻止用作锁的对象(监视器,我们称之为它lock)在这些块之外使用,在这种情况下不会执行同步。例如,一个线程可以读取或写入,而另一个线程位于监视器lock所在的同步块内。lock

如果要限制对变量的访问,则需要确保在持有锁时进行所有访问(任何锁,只要每次访问都相同)。

于 2013-01-21T21:01:48.677 回答
3

使方法同步有两个效果:

首先,同一对象上的同步方法的两次调用不可能交错。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

其次,当同步方法退出时,它会自动与任何后续对同一对象的同步方法调用建立起之前的关系。这保证了对象状态的更改对所有线程都是可见的。

(来源:Java 教程

于 2013-01-21T21:16:39.893 回答