Java中如何对静态方法JobQueue.getByte()实现互斥?
Java多线程互斥问题:确保JobQueue.getByte()单线程访问避免重复值
你的核心问题是JobQueue.getByte()方法的临界区未被完整同步。当前代码中,多个线程可同时进入方法,读取同一个nextByte值后各自修改,导致返回重复的byte数组;同时直接返回数组引用的操作,会让后续修改覆盖已返回的内容,进一步加剧重复问题。
解决方案1:用synchronized修饰静态方法
直接给getByte()加synchronized修饰符,锁的是JobQueue.class对象,确保同一时间只有一个线程执行整个方法的逻辑:
修改后的JobQueue类关键代码:
public class JobQueue{ private static volatile Byte[] nextByte; private static final Byte realMin = 0; private static final Byte realMax = (byte) 89; // 省略initJobQueue和checkEndVal方法 public static synchronized Byte[] getByte(){ if(nextByte==null || checkEndVal(nextByte)) return null; // 克隆数组,避免返回引用被后续修改覆盖 Byte[] currentByte = nextByte.clone(); // 迭代递增逻辑 for (int i = 0; i < nextByte.length; i++) { // 用equals避免Byte装箱类型的==比较问题 if (nextByte[i].equals(realMax)){ nextByte[i] = realMin; } else{ nextByte[i]++; break; } } if(checkEndVal(nextByte)) nextByte=null; return currentByte; } }
对应的ByteIterator的run方法可简化,无需额外加锁:
@Override public void run(){ Byte[] foo = JobQueue.getByte(); while(foo != null){ System.out.println(Arrays.toString(foo)); foo = JobQueue.getByte(); } }
解决方案2:用ReentrantLock实现显式锁
如果需要更灵活的锁控制(如公平锁、超时锁),可使用显式锁包裹整个临界区:
修改后的JobQueue类关键代码:
import java.util.concurrent.locks.ReentrantLock; public class JobQueue{ private static volatile Byte[] nextByte; private static final Byte realMin = 0; private static final Byte realMax = (byte) 89; private static final ReentrantLock lock = new ReentrantLock(); // 省略initJobQueue和checkEndVal方法 public static Byte[] getByte(){ lock.lock(); try { if(nextByte==null || checkEndVal(nextByte)) return null; Byte[] currentByte = nextByte.clone(); for (int i = 0; i < nextByte.length; i++) { if (nextByte[i].equals(realMax)){ nextByte[i] = realMin; } else{ nextByte[i]++; break; } } if(checkEndVal(nextByte)) nextByte=null; return currentByte; } finally { lock.unlock(); // 确保锁一定会释放,避免死锁 } } }
你之前尝试失败的原因
- 同步范围不完整:仅在
ByteIterator的后续调用加锁,但第一次getByte()调用在同步块外,存在初始竞争;且getByte()内部的读、复制、修改操作未被原子化,线程仍会交错执行。 - 数组引用直接返回:未克隆数组,导致返回的数组会被后续修改覆盖,看起来像是重复值(实际是同一数组被多次打印,内容已变更)。
- Byte类型比较问题:用
==比较装箱后的Byte对象,会因缓存范围(-128~127)导致非预期的相等判断,改用equals()可避免此问题。
内容的提问来源于stack exchange,提问作者rawPancakes
相关产品推荐
相关产品推荐

