You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中循环数组场景下如何将synchronized迁移为ReentrantLock

虚拟线程下将Synchronized块迁移为ReentrantLock的实践

根据Java 21+的《JEP 444: 虚拟线程》规范,当代码中存在频繁执行且包含潜在长时间I/O操作的synchronized同步块/方法时,需要将其替换为java.util.concurrent.locks.ReentrantLock,以避免虚拟线程的线程固定问题——虚拟线程在持有synchronized锁期间会绑定到平台线程,若锁内存在长时间I/O,会占用宝贵的平台线程资源,无法发挥虚拟线程的轻量优势。

下面针对提供的示例代码,逐一说明迁移步骤:


一、重构后代码(ControllerCell类)迁移方案

原始同步逻辑

原代码通过synchronized (cells[i][j])锁定每个ObjectCell实例,执行update操作:

synchronized (cells[i][j]) {
    cells[i][j].update(subimage);
}

迁移步骤

  1. 修改ObjectCell类,添加ReentrantLock成员变量:
import java.util.concurrent.locks.ReentrantLock;

public class ObjectCell {
    private final ReentrantLock lock = new ReentrantLock();
    // 原有成员变量...

    // 改写update方法,使用ReentrantLock保护临界区
    public void update(BufferedImage subimage) {
        lock.lock();
        try {
            // 原update方法的业务逻辑
        } finally {
            lock.unlock(); // 确保锁在任何情况下都会释放
        }
    }
}
  1. 修改ControllerCell的processImage方法,移除synchronized块,直接调用update:
// 替换原有synchronized块
cells[i][j].update(subimage);

如果希望将锁的控制保留在ControllerCell侧而非ObjectCell内部,也可以这样实现:

// 在ControllerCell的processImage中直接操作锁
ReentrantLock cellLock = cells[i][j].getLock(); // 需要ObjectCell提供获取锁的方法
cellLock.lock();
try {
    cells[i][j].update(subimage);
} finally {
    cellLock.unlock();
}

二、原始代码(TileManager + Tile类)迁移方案

原始同步逻辑

原TileManager通过synchronized (tiles[i][j])锁定Tile实例,执行updateImage2操作:

synchronized (tiles[i][j]) {
    changed = tiles[i][j].updateImage2(subimage);
    // 日志逻辑...
}

迁移步骤

  1. 修改Tile类,添加ReentrantLock成员变量:
import java.util.concurrent.locks.ReentrantLock;

public class Tile {
    private final ReentrantLock lock = new ReentrantLock();
    // 原有成员变量:stream、checksum等...

    // 改写updateImage2方法,用ReentrantLock保护临界区
    public boolean updateImage2(BufferedImage image) {
        lock.lock();
        try {
            long oldsum = checksum.getValue();
            calcChecksum2(image);
            if (oldsum != checksum.getValue()) {
                if (DEBUG) System.out.println(getClass().getName() + ": Version changed [" + stream.size() +"]");
                stream.reset();
                writeImage(image, stream);
                version++;
                dirty = true;
                return true;
            } else {
                if (DEBUG) System.out.println(getClass().getName() + ": Version unchange");
                return false;
            }
        } finally {
            lock.unlock();
        }
    }

    // 若需要外部控制锁,可添加获取锁的方法
    public ReentrantLock getLock() {
        return lock;
    }

    // 原有其他方法保持不变...
}
  1. 修改TileManager的processImage方法,移除synchronized块:
// 替换原有synchronized块
changed = tiles[i][j].updateImage2(subimage);
if (DEBUG) {
    if (changed) System.out.println(getClass().getName() + ": [" + i + "," + j + "] Changed. ["+tiles[i][j].fileSize()+"]");
}

如果希望将日志逻辑也纳入锁的保护范围(保持原有同步粒度),则需要在TileManager中获取Tile的锁:

ReentrantLock tileLock = tiles[i][j].getLock();
tileLock.lock();
try {
    changed = tiles[i][j].updateImage2(subimage);
    if (DEBUG) {
        if (changed) System.out.println(getClass().getName() + ": [" + i + "," + j + "] Changed. ["+tiles[i][j].fileSize()+"]");
    }
} finally {
    tileLock.unlock();
}

关键注意事项

  • 必须使用try-finally:无论临界区代码是否抛出异常,都要保证锁被释放,避免死锁。
  • 锁的粒度保持一致:迁移时确保临界区范围与原synchronized块完全一致,避免出现并发问题。
  • ReentrantLock的特性:它支持公平锁、可中断锁等高级特性,若不需要可使用默认的非公平锁(性能更优)。

内容的提问来源于stack exchange,提问作者Tugalsan Karabacak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 23:13:11