Java中如何在不同类实例启动的线程间共享锁同步执行?
问题描述
我尝试在Application类中创建一个共享锁,并将其传递给创建线程的方法参数,希望让一个类实例启动的线程与另一个类实例启动的线程实现同步。
抽象类Alpha的start(Object sharedLock)方法用于创建新线程,原代码如下:
public abstract class Alpha { public abstract void test(); public void start(Object sharedLock) { Thread t = new Thread(() -> { while(true) { synchronized(sharedLock) { test(); } try { TimeUnit.SECONDS.sleep(db.timeInterval); } catch(InterruptedException e) { Thread.currentThread().interrupt(); } } }); t.start(); // 原代码遗漏线程启动逻辑 } }
Alpha有两个子类Beta和Gama,Application类的run方法调用它们的start()方法:
@Override public void run(String... args) { Object sharedLock = new Object(); // 补充共享锁实例创建 Beta beta = new Beta(); Gama gama = new Gama(); beta.start(sharedLock); gama.start(sharedLock); }
Beta和Gama重写了test()方法:
public class Beta extends Alpha { @Override public void test() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); final int[] count = {1}; Runnable task = new Runnable() { @Override public void run() { System.out.println(count[0]); count[0]++; if (count[0] > 20) { executor.shutdown(); } } }; executor.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS); } } public class Gama extends Alpha { @Override public void test() { System.out.println("Gama thread"); } }
需求:同一时间仅能有一个线程执行test()相关逻辑,例如Beta先获取锁的话,要完整打印1到20后,Gama才能执行;同时当持有锁的线程休眠时,其他线程可获取锁执行。
问题分析
原代码核心问题:
- Beta的
test()仅完成定时任务的提交,synchronized块只保护了任务提交过程,没有覆盖定时任务的整个执行周期。synchronized块执行完test()后就释放锁,此时Gama的线程会立刻进入同步块执行自己的逻辑,导致Beta的定时任务和Gama的输出同时进行。 - Alpha中的
while(true)会不断重复进入同步块调用test(),即使Beta的定时任务还未完成,会重复创建线程池和提交任务,造成逻辑混乱。
解决方案
要实现需求,需确保Beta的整个定时任务周期都被共享锁保护,同时调整Alpha的循环逻辑避免重复执行。具体修改如下:
1. 调整Alpha类
修改逻辑,让每个线程按需执行同步逻辑,同时预留循环执行的扩展空间:
public abstract class Alpha { public abstract void executeWithLock(Object sharedLock); public void start(Object sharedLock) { Thread t = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { try { executeWithLock(sharedLock); // 执行完成后休眠,休眠期间锁被释放,其他线程可竞争 TimeUnit.SECONDS.sleep(db.timeInterval); } catch(InterruptedException e) { Thread.currentThread().interrupt(); break; } } }); t.start(); } }
2. 修改Beta类
将同步范围覆盖到定时任务的整个执行周期,等待任务全部完成后再释放锁:
public class Beta extends Alpha { @Override public void executeWithLock(Object sharedLock) { synchronized(sharedLock) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); final int[] count = {1}; Runnable task = new Runnable() { @Override public void run() { System.out.println(count[0]); count[0]++; if (count[0] > 20) { executor.shutdown(); } } }; executor.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS); // 等待线程池所有任务完成,确保整个打印过程都在锁保护下 try { executor.awaitTermination(1, TimeUnit.HOURS); // 设置足够长的超时时间 } catch (InterruptedException e) { Thread.currentThread().interrupt(); executor.shutdownNow(); } } } }
3. 修改Gama类
在共享锁保护下执行自身逻辑:
public class Gama extends Alpha { @Override public void executeWithLock(Object sharedLock) { synchronized(sharedLock) { System.out.println("Gama thread"); } } }
关键说明
- 必须将所有需要同步的逻辑都放在共享锁的保护范围内,对于Beta来说,就是从任务创建到全部完成的完整流程。
- 使用
executor.awaitTermination()等待定时任务结束,避免提前释放锁导致同步失效。 - Alpha的循环逻辑确保线程执行完一次任务后休眠,休眠期间锁被释放,其他线程可以竞争获取锁执行,符合需求。
内容的提问来源于stack exchange,提问作者ot954
相关产品推荐
相关产品推荐

