Java:能够调用处于其他线程的同步块中的方法的线程

时间:2019-01-26 19:38:37

标签: java thread-safety java-threads thread-synchronization synchronisation

线程t1正在调用Test类对象ob的test1()方法。
线程t2在同步块中调用Test类对象ob的test1()方法。
即使t1的方法调用位于线程test1()的同步块中,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 :(得分:0)

由于NewThread1#run()未同步,因此它不会尝试将监视器放在目标上,因此不会被阻塞,即使另一个线程持有该监视器,它也可以在目标上调用该方法。 / p>

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!");
        }
    }
}