为何调用synchronized方法未阻塞MyThread对象?
Synchronized方法的理解误区解析
问题描述
调用mt1.method()时预期会阻塞MyThread对象,但实际并未发生。当run方法中使用普通for循环时,主线程与Thread-0交替执行;若将run方法中的for循环替换为调用synchronized修饰的method(),则会按预期顺序执行。请问对synchronized方法的理解哪里有误?
相关代码
class MyThread implements Runnable { public Thread thrd; public MyThread() { thrd = new Thread(this); } public static MyThread createAndRun() {//Test t MyThread mt = new MyThread(); mt.thrd.start(); return mt; } @Override public void run() { // This way main thread doesn't block MyThread. for (int i = 0; i < 10; ++i) { System.out.print(Thread.currentThread().getName() + ":" + i + " "); try { Thread.sleep(250); } catch (InterruptedException exception) { exception.printStackTrace(); } } //main:0 Thread-0:0 main:1 Thread-0:1 main:2 Thread-0:2 main:3 Thread-0:3 main:4 Thread-0:4 main:5 Thread-0:5 Thread-0:6 main:6 Thread-0:7 main:7 Thread-0:8 main:8 Thread-0:9 main:9 // method();// if use it instead for-lopp - all works as expected. //main:0 main:1 main:2 main:3 main:4 main:5 main:6 main:7 main:8 main:9 Thread-0:0 Thread-0:1 Thread-0:2 Thread-0:3 Thread-0:4 Thread-0:5 Thread-0:6 Thread-0:7 Thread-0:8 Thread-0:9 } synchronized public void method() { for (int i = 0; i < 10; ++i) { System.out.print(Thread.currentThread().getName() + ":" + i + " "); try { Thread.sleep(250); } catch (InterruptedException exception) { exception.printStackTrace(); } } } } class App { public static void main(String[] args) { MyThread mt1 = MyThread.createAndRun(); mt1.method(); try { mt1.thrd.join(); } catch (InterruptedException exc) { System.out.println(exc); } } }
误区解析
核心错误是误以为synchronized会锁住整个对象,阻止其他线程执行该对象的所有代码,但实际上synchronized只保护被它修饰的代码块/方法,未被同步的代码不受锁的约束:
- 当run方法使用普通for循环时,这个循环没有被同步锁保护。主线程调用
mt1.method()时,虽然拿到了mt1对象的锁,但Thread-0执行的是无锁的for循环,完全不受锁的影响,两个线程各自独立执行,因此出现交替输出的情况。 - 当run方法替换为调用
method()时,Thread-0要执行这个同步方法,必须先获取mt1对象的锁。而主线程已经先调用了mt1.method()并持有锁,直到主线程执行完method()才会释放锁。Thread-0只能等待锁释放后才能执行,因此出现主线程先输出完毕,再轮到Thread-0输出的顺序。
简言之:synchronized的作用范围仅限于被它修饰的代码,不是对整个对象的全局阻塞。
内容的提问来源于stack exchange,提问作者Squared
相关产品推荐
相关产品推荐

