0

我是同步和多线程的新手,请回答为什么这段代码没有锁定对象 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

4 回答 4

4

readObject方法(包括从 调用A2#run)不涉及锁获取。因此,您的其他线程持有的锁对于readObject.

显然你对锁的语义有误解。你相信当你锁定时B.class,你就锁定了“全班”。事情的状态是完全不同的:B.class只是另一个对象,并且所有对象都有其关联的监视器,可以由线程获取。互斥只发生在争用 同一个锁的线程之间。作为锁的对象与其任何方法之间没有语义关系,类对象vz也是如此。该类的实例。

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

于 2013-09-24T10:19:30.823 回答
2

它的行为符合预期。这是时间线上发生的事情

a- 调用等待(在释放锁之前休眠 5 秒) a2- 调用 read 打印读取消息。

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

您的设备中没有任何类型的锁定readObject()

于 2013-09-24T10:24:06.367 回答
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());
        }
    }
} 
于 2013-09-24T10:58:42.477 回答
0

由于readObject()不需要获取锁,它不会等待其他线程释放锁。这种混乱可能是因为Thread.sleep(2000)你在你的测试课上。

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

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

在第二种情况下,线程将在启动后A2等待10 秒A,在这10 秒内,您A将启动,休眠5 秒并释放锁,之后您A2将毫无延迟地执行。

于 2013-09-24T10:23:52.690 回答