为什么在获取对象锁定时会调用非同步方法?

时间:2013-09-24 10:14:44

标签: java multithreading

我是同步和多线程的新手,请回答为什么这段代码没有锁定对象b。

public class Tetsclass {

    public static void main(String[] args) {
        B b = new B();
        A a = new A(b);
        A2 a2 = new A2(b);
        Thread t1= new Thread(a);
        Thread t2= new Thread(a2);
        t1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        t2.start();
    }
}
class B {
    public synchronized void waitfor() {        
        synchronized (B.class) {
            System.out.println("Lock aquired  on "+System.currentTimeMillis());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {      
                e.printStackTrace();
            }
            System.out.println("Lock released");
        }

    }
    public void readObject() {
        System.out.println("readobject by thread==="+Thread.currentThread().getName()+" on "+System.currentTimeMillis());

    }
}
class A2 implements Runnable {

    B b=null;
    public A2(B b) {
        this.b = b;
    }

    @Override
    public void run() {     
        b.readObject();     
    }
}
class A implements Runnable {

    B b=null;
    public A(B b) {
        this.b = b;
    }
    @Override
    public void run() {             
        b.waitfor();                
    }
}

我期待输出:

Lock aquired  on 1380016080337
Lock released
readobject by thread===Thread-1 on 1380016082337

但输出是:

Lock aquired  on 1380016080337
readobject by thread===Thread-1 on 1380016082337
Lock released

4 个答案:

答案 0 :(得分:4)

readObject方法,包括从A2#run调用,不涉及锁定获取。因此,您的其他线程持有的锁对readObject的执行进度无关紧要。

显然你对锁的语义有误解。你相信当你锁定B.class时,你已经锁定了“全班”。问题的状态完全不同:B.class只是另一个对象,所有对象都有相关的监视器,可以通过线程获取。相互排除仅发生在争用获取 1和相同锁的线程之间。作为锁的对象与其任何方法之间没有语义关系,并且同样代表类对象vz。该类的实例。

可能出现误解的一种方法是通过synchronized方法隐式使用的对象:同步实例方法获取其this作为锁,而同步静态方法获取其关联的锁类对象。

答案 1 :(得分:2)

表现如预期。 以下是时间线上发生的事情

a - 呼叫等待(在释放锁定之前休眠5秒) a2 - 调用读取打印读取消息的内容。

          t          t+dt                                                 t+dt+5
 ---------|-----------|--------------------------------|--------------------------|----------
      [a starts] [print(lock acquired)]             [sleeps(5)]           [print(lock released)]
                            t+2
 ----------------------------|--------------|--------------------------|--------------
                         [a2 starts]   [print(read message)]

readObject()

中没有任何类型的锁定

答案 2 :(得分:0)

由于readObject()不需要获取锁,因此它不会等待另一个线程释放锁。由于您在测试类中Thread.sleep(2000),可能会出现这种混淆。

尝试将其更改为Thread.sleep(10000)并查看输出。你会得到你想要的结果。

在第一种情况下,A2线程会在A启动后等待 2秒,并且会在没有任何进一步延迟的情况下执行,而您的A是获得锁定后,持续 5秒

在第二种情况下,A2线程将在A启动后等待 10秒,并且在 10秒之内,您的{ {1}}将启动,睡眠 5秒并释放锁定,之后您的A将会毫不拖延地执行。

答案 3 :(得分:0)

可以同步B类对象以获得预期的输出。当前代码执行中不涉及同步。要同步此代码并获得预期输出,我们可以将B类修改为

class B {
    public synchronized void waitfor() {        
        synchronized (B.class) {
            System.out.println("Lock aquired  on "+System.currentTimeMillis());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {      
                e.printStackTrace();
            }
            System.out.println("Lock released");
        }

    }
    public void readObject() {
        synchronized(B.class)
        {
        System.out.println("readobject by thread==="+Thread.currentThread().getName()+" on "+System.currentTimeMillis());
        }
    }
}