synchronized块没有锁定对象引用
class Demo { void demo() { System.out.println("Inside demo of "+Thread.currentThread().getName()); try { Thread.sleep(1000000); } catch(InterruptedException exc) { System.out.println(Thread.currentThread().getName()+" interrupted"); } } } class MyThread1 implements Runnable { Thread thread; Demo d; MyThread1(String name, Demo ob) { d = ob; thread = new Thread(this, name); thread.start(); } @Override public void run() { System.out.println(thread.getName()+" starting"); synchronized(d) { d.demo(); } System.out.println(thread.getName()+" ending"); } } class MyThread2 implements Runnable { Thread thread; Demo d; MyThread2(String name, Demo ob) { d = ob; thread = new Thread(this, name); thread.start(); } @Override public void run() { System.out.println(thread.getName()+" starting"); d.demo(); System.out.println(thread.getName()+" ending"); } } class TimePass { public static void main(String args[]) { Demo d = new Demo(); MyThread1 mt1 = new MyThread1("Thread 1", d); MyThread2 mt2 = new MyThread2("Thread 2", d); } }
输出是
线程1开始
线程1的内部演示
线程2开始
线程2的内部演示
由于Thread.sleep(1000000)
,执行尚未结束。
我已经将类Demo
的相同实例传递给了MyThread1
和MyThread2
类的构造函数。
Demo d = new Demo(); MyThread1 mt1 = new MyThread1("Thread 1", d); MyThread2 mt2 = new MyThread2("Thread 2", d);
在MyThread1
对d.demo
的调用是在synchronized
块中。
MyThread2
对d.demo
的调用不在 synchronized
块中。
因此,当MyThread1
正在执行时,由于synchronized
块, d
的监视器应该被锁定,导致MyThread2
拒绝访问d.demo()
。
但这不会发生。
预期的产出是
Thread 1 starting Inside demo of Thread1 Thread 2 starting
(输出在Thread.sleep(1000000)
完成之前。)
所以,我的基本问题是: 即使MyThread1.d.demo()
尚未完成synchronized
块, MyThread2.d.demo()
如何成功执行?
因此,当MyThread1正在执行时,由于
synchronized
块,d
的监视器应该被锁定,导致MyThread2拒绝访问d.demo()
。
只有当MyThread2也有一个synchronized
块时才会发生这种情况。 当一个线程在一个对象上同步时,如果其他线程也尝试在同一个对象上进行同步,则会阻塞其他线程。 如果他们不同步,他们就不会。 没有任何东西可以阻止从不同步的线程访问对象。
同步是一种合作机制。 它仅在所有线程协同工作时有效。
synchronization
仅发生在Thread1
。 由于Thread2
不在d
synchronize
,因此允许在Thread1持有锁时调用demo()
。
你似乎误解了synchronized
的使用。 仅与尝试进入公共对象的同步块的其他线程同步。
同步是一种协作努力。 每一方都声明,当另一方处于关键部分时,他们就不会。
您只在一个线程中synchronized
访问Demo
实例的demo
方法
synchronized(d) { d.demo(); }
另一个是直接访问它
d.demo();
他们打破了这些协作规则,因此您无法承担任何责任。
这在JLS中有解释
获取与对象关联的锁本身不会阻止其他线程访问对象的字段或在对象上调用未同步的方法。 其他线程也可以以常规方式使用同步方法或同步语句来实现互斥。