Java 为什么在获取对象锁时调用非同步方法?
我不熟悉同步和多线程。请回答为什么这段代码没有锁定对象bJava 为什么在获取对象锁时调用非同步方法?,java,multithreading,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);
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
readObject
方法,包括从A2#run
调用,不涉及锁获取。因此,另一个线程持有的锁对执行readObject
的进度无关紧要
显然你对锁的语义有误解。您认为当您锁定B.class
时,您已经锁定了“整个类”。事情的状态完全不同:B.class
只是另一个对象,所有对象都有其关联的监视器,可以通过线程获取。互斥只发生在争用同一个锁的线程之间。作为锁的对象和它的任何方法之间都没有语义关系,这同样代表类对象vz。该类的实例
您可能产生误解的一种方式是通过
synchronized
方法上隐式使用的对象:同步实例方法获取其this
作为锁,而同步静态方法获取其关联类对象上的锁。,包括从A2#run
调用它,不涉及锁获取。因此,另一个线程持有的锁对执行readObject
的进度无关紧要
显然你对锁的语义有误解。您认为当您锁定B.class
时,您已经锁定了“整个类”。事情的状态完全不同:B.class
只是另一个对象,所有对象都有其关联的监视器,可以通过线程获取。互斥只发生在争用同一个锁的线程之间。作为锁的对象和它的任何方法之间都没有语义关系,这同样代表类对象vz。该类的实例
您可能产生误解的一种方式是通过synchronized
方法上隐式使用的对象:同步实例方法获取其this
作为锁,而同步静态方法获取其关联类对象上的锁。因为readObject()
不需要获取锁,它不会等待其他线程释放锁。这种混乱可能是由于您在测试类中使用了Thread.sleep(2000)
尝试将其更改为Thread.sleep(10000)
,然后查看输出。你会得到你想要的结果
在第一种情况下,A2
线程将在A
启动后等待2秒,并将不再延迟地执行,而您的A
在获得锁时将被延迟5秒
在第二种情况下,A2
线程将在A
启动后等待10秒,在这些10秒内,您的A
将启动,休眠5秒,然后释放锁,之后,您的A2
将无延迟地执行。由于readObject()
不需要获取锁,因此它不会等待其他线程释放锁。这种混乱可能是由于您在测试类中使用了Thread.sleep(2000)
尝试将其更改为Thread.sleep(10000)
,然后查看输出。你会得到你想要的结果
在第一种情况下,A2
线程将在A
启动后等待2秒,并将不再延迟地执行,而您的A
在获得锁时将被延迟5秒
在第二种情况下,A2
线程将在A
启动后等待10秒,在这些10秒内,您的A
将启动,休眠5秒,然后释放锁,之后,您的A2
将毫无延迟地执行。其行为符合预期。
下面是在时间线上发生的事情
a
-呼叫等待(在释放锁之前休眠5秒)
a2
-调用read,打印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()
中没有任何类型的锁定,其行为符合预期。
下面是在时间线上发生的事情
a
-呼叫等待(在释放锁之前休眠5秒)
a2
-调用read,打印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()
类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());
}
}
}
类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());
}
}
}
是的,但在调用syncronized方法时,它将获取整个对象的锁。那么为什么要调用这个readObject呢?你确定你已经完整地阅读了我的答案吗?在我的第二和第三段中详细回答了您的上述问题。是的,但在调用syncronized方法时,它将获得整个对象的锁。那么为什么要调用这个readObject呢?你确定你已经完整地阅读了我的答案吗?我在第二和第三段详细回答了你的上述问题。