使用同一类不同实例调用synchronized方法的执行逻辑及顺序控制
synchronized修饰实例方法多实例调用逻辑及顺序执行方案
原示例代码
public class A1 { public synchronized void m1(){ try{ Thread.sleep(5000); }catch(Exception e){ } } public static void main(String[] args) { A1 o1 = new A1(); A1 o2 = new A1(); o1.m1(); o2.m1(); } }
现有场景执行逻辑
synchronized修饰实例方法时,绑定的锁对象是当前方法所属的实例本身(即this),因此不同实例的同步方法持有的锁完全独立:
- 你给出的示例是在main主线程中顺序调用两个实例的
m1方法,本身就会按代码顺序执行:先执行完o1的m1方法(阻塞5秒),再执行o2的m1方法(再阻塞5秒),总耗时约10秒。 - 如果是启动两个独立线程分别调用
o1.m1()和o2.m1(),两个线程不存在锁竞争,会并行执行,总耗时约5秒,执行顺序由CPU调度决定,无法保证固定顺序。
强制两次调用按顺序执行的方案
如果是多线程调用场景下需要保证两个实例的m1方法按指定顺序执行,可参考以下方案:
方案1:替换为类级别锁
修改方法的锁粒度为类级别,所有实例调用该方法都需要竞争同一个类锁,天然保证串行执行:
public class A1 { // 方式1:改为静态同步方法,锁对象为A1.class public static synchronized void m1(){ try{ Thread.sleep(5000); }catch(Exception e){ } } // 方式2:不修改方法静态属性,方法内部加类锁 public void m1(){ synchronized(A1.class){ try{ Thread.sleep(5000); }catch(Exception e){ } } } }
方案2:调用侧使用共享锁
不修改原有A1类的代码,在调用层定义全局共享的锁对象,两个调用都需要先获取该锁才能执行:
public static void main(String[] args) { A1 o1 = new A1(); A1 o2 = new A1(); // 共享锁对象 Object sharedLock = new Object(); new Thread(() -> { synchronized (sharedLock) { o1.m1(); } }).start(); new Thread(() -> { synchronized (sharedLock) { o2.m1(); } }).start(); }
方案3:使用线程协调工具
用CountDownLatch等JUC工具实现前一个执行完成后再触发后一个调用,顺序可控:
import java.util.concurrent.CountDownLatch; public static void main(String[] args) throws InterruptedException { A1 o1 = new A1(); A1 o2 = new A1(); CountDownLatch latch = new CountDownLatch(1); // 先执行o1的调用 new Thread(() -> { o1.m1(); latch.countDown(); }).start(); // 等待o1执行完成后再启动o2的调用 latch.await(); new Thread(() -> o2.m1()).start(); }
内容的提问来源于stack exchange,提问作者Saurav Shrivastav
相关产品推荐
相关产品推荐

