Java: поток может вызвать метод, который находится в синхронизированном блоке другого потока - PullRequest
0 голосов
/ 26 января 2019

thread t1 вызывает test1() метод объекта класса Test ob.
поток t2 вызывает test1() метод объекта класса Test ob в синхронизированном блоке.
t1 может вызывать test1() метод ob, даже если test1() вызов метода ob находится в синхронизированном блоке потока t2.

Код указан ниже:

class Test {
    void test1() {
        while(1 == 1) {
            System.out.println(Thread.currentThread().getName() + " test1!");
        }
    }

    void test2() {
        while(1 == 1) {
            System.out.println(Thread.currentThread().getName() + " test2!");
        }
    }
}

class NewThread1 implements Runnable {
    Thread t;
    String name;
    Test target;

    NewThread1(Test ob, String threadname) {
        target = ob;
        name = threadname;
        t = new Thread(this, name);
    }

    public void run() {
        target.test1();
    }
}

class NewThread2 implements Runnable {
    Thread t;
    String name;
    Test target;

    NewThread2(Test ob, String threadname) {
        target = ob;
        name = threadname;
        t = new Thread(this, name);
    }

    public void run() {
        synchronized(target) {
            target.test1();
        }
    }
}

class Test1 {
    public static void main(String args[]) {
        Test ob = new Test();
        NewThread1 t1 = new NewThread1(ob, "t1");
        NewThread2 t2 = new NewThread2(ob, "t2");

        t2.t.start();
        t1.t.start();

        try {
            t1.t.join();
            t2.t.join();
        } catch(InterruptedException e) {
            System.out.println("Main thread interrupted");
        }

        System.out.println("Main thread exiting");
    }
}

1 Ответ

0 голосов
/ 26 января 2019

Поскольку NewThread1#run() не синхронизирован, он не будет пытаться установить монитор на цель и поэтому не будет заблокирован, он может вызвать метод на цели, даже если другой поток удерживает его монитор.

Synchronized может блокировать только другие потоки, только если все потоки конкурируют с одним монитором с синхронизированным разделом.(Неважно, вызовите ли вы test1 или test2, проверка происходит при синхронизации на основе цели).Вы можете сделать синхронизированные методы test1 и test2, после чего они попытаются зарезервировать монитор экземпляра во всех случаях).То же самое верно не только для исключительного выполнения, но и для любых гарантий доступа к памяти (происходит после), которые вы можете захотеть получить из синхронизированного блока.

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

Thread t1 = new NewThread2(ob, "t1");
Thread t2 = new NewThread2(ob, "t2");

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

void synchronized test1() {
    while(1 == 1) {
        System.out.println(Thread.currentThread().getName() + " test1!");
    }
}

или

void test1() {
    synchronized(this) {
        while(1 == 1) {
            System.out.println(Thread.currentThread().getName() + " test1!");
        }
    }
}
...