Включает ли монитор Java переменные экземпляра?

Это тот факт, что монитор в 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();
    }
}

Вывод программы ниже:

 
Okay, I am in sync() method. I will be waiting for 10 seconds. Current Time = 1358801766310  
Alright, I am in unsync() method. The current time is 1358801768343. The time of exit from unsync() method is 1358801768343  
Okay, I have waited for 10 seconds. Current time is 1358801776310. Now I will exit from sync() method, a = 11

Ответ 1

Да. Удержание монитора объекта препятствует тому, чтобы другой поток выполнял другой блок кода или синхронизировался на одном и том же объекте. Если метод не синхронизирован, любой поток может вызвать его в любой момент, независимо от того, содержит ли другой поток монитор или нет.

Каждый доступ к общему заявленному, даже доступному только для чтения, должен быть синхронизирован, если есть вероятность, что хотя бы один поток изменяет это общее состояние.

Ответ 2

Является ли этот монитор в java не ограничивает доступ к переменным экземпляра и только к методам, которые объявлены синхронизированными или кодами в синхронизированных операторах?

Да.

Синхронизированные блоки (или методы), между прочим, являются взаимоисключающими. Это не мешает использовать объект в качестве блокировки (монитор, пусть его называют lock), который будет использоваться вне этих блоков, и в этом случае синхронизация не будет выполнена. Например, один поток может читать или писать lock, тогда как другой поток находится в синхронизированном блоке, где lock является монитором.

Если вы хотите ограничить доступ к переменной, вам необходимо убедиться, что все обращения выполняются при блокировке (любая блокировка при условии, что она одинакова для каждого доступа).

Ответ 3

Синхронизация синхронных методов имеет два эффекта:

Во-первых, невозможно, чтобы две вызовы синхронизированных методов на одном объекте чередовали. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же объекта (приостанавливать выполнение) до тех пор, пока первый поток не будет выполнен с объектом.

Во-вторых, когда синхронизированный метод завершается, он автоматически устанавливает связь между событиями и последующим вызовом синхронизированного метода для одного и того же объекта. Это гарантирует, что изменения состояния объекта будут видны для всех потоков.

(источник: учебные пособия по Java)