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