Java多线程疑问:为何Thread2可在Thread1未退出时进入同步方法?
问题:同步方法为何未按预期实现线程互斥?
示例代码
public class MyThread extends Thread { public synchronized void logic() { System.out.println("Thread started"); System.out.println(Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread ended"); } public void run() { System.out.println("inside run method"); logic(); } public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); MyThread thread3 = new MyThread(); thread1.start(); thread2.start(); thread3.start(); } }
运行输出
inside run method inside run method Thread started inside run method Thread-1 Thread started Thread-0 Thread started Thread-2 <<<After few seconds>>> Thread ended Thread ended Thread ended
疑问点
调用thread.start()后,所有线程都能进入run方法;logic方法是synchronized同步方法,按理解当一个线程进入同步方法时,其他线程需等待该线程执行完毕才能进入。但从输出可见,Thread-1进入logic方法并打印“Thread started”且未执行完毕时,Thread-0、Thread-2也能进入logic方法并打印“Thread started”,为何会出现这种情况?预期应该是只有当没有线程处于logic方法中时,其他线程才能进入该方法。
原因解析
核心问题出在同步锁的对象范围上:
- 当
synchronized修饰实例方法时,它的锁是当前对象实例(this)。 - 代码里创建了三个独立的
MyThread对象:thread1、thread2、thread3,每个线程对应的锁是各自的对象实例,这三个锁完全互不关联。 - 所以每个线程进入
logic方法时,获取的是自己对象的锁,不会和其他线程的锁产生竞争,自然不需要等待其他线程执行完毕,多个线程可以同时进入各自的logic方法。
解决方法
如果要让所有线程共用同一把锁,实现互斥执行logic方法,有两种常见方案:
- 将
logic方法改为静态同步方法:静态方法的锁是当前类的Class对象(MyThread.class),所有线程共用这一把锁。public static synchronized void logic() { // 方法内容不变 } - 在实例方法中,使用类对象作为锁:
public void logic() { synchronized(MyThread.class) { // 原方法内容放在同步代码块内 System.out.println("Thread started"); System.out.println(Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread ended"); } }
内容的提问来源于stack exchange,提问作者Asif Sk
相关产品推荐
相关产品推荐

