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

如何正确使用synchronized指令解决TextView不同步问题?

问题分析与解决方案

核心问题根源

你遇到的罗马音与片假名TextView不同步问题,本质是共享成员变量pickFromArray被多次修改导致的。当QandA方法被多次触发(比如SetQuestion在短时间内两次调用QandA,或按钮闪烁逻辑涉及修改该变量)时,这个共享变量的索引值会被覆盖,导致设置罗马音和片假名时使用了不同的索引,最终显示不匹配。

而你之前加的synchronized无效,是因为所有UI操作都在主线程执行,主线程是单串行模型,不存在多线程竞争场景,synchronized在这里无法起到预期的原子性保障作用。


解决方案

1. 将索引改为局部变量(最直接有效)

把pickFromArray改为QandA方法内的局部变量,让每个QandA调用使用独立的索引,彻底避免共享变量的干扰:

public void QandA(){
    // 用局部变量存储随机索引,每个调用独立不冲突
    int localPick = ThreadLocalRandom.current().nextInt(0, arraySize);
    textView29.setText(listromT.get(localPick));
    hintView.setText(listT.get(localPick));
}

这种方式从根源上保证了罗马音和片假名始终使用同一个索引,完全无需依赖锁机制。

2. 移除冗余的runOnUiThread调用

你的SetQuestion Runnable已经通过主线程Handler.postDelayed执行,本身就在主线程运行,嵌套runOnUiThread属于冗余操作,可能导致任务调度混乱。修改后的代码:

public Runnable SetQuestion = new Runnable() {
    @Override
    public void run() {
        Qtimer++;
        // 合并条件判断,简化代码
        if (Qtimer % 10 == 1 || Qtimer % 10 == 6) {
            QandA();
        }
        if (Qtimer > 199) {
            Qtimer = 110;
        }
        // 直接将当前Runnable post到主线程队列
        handler.postDelayed(this, 1000);
    }
};

注意:确保你的handler是通过主线程Looper初始化的,比如handler = new Handler(Looper.getMainLooper()),保证任务在主线程执行。

3. 关于synchronized的正确使用场景

synchronized仅适用于多线程访问共享资源的场景,比如后台线程和主线程同时修改同一个数据。而你的所有UI操作都在主线程执行,主线程的代码是串行执行的,不存在并发冲突,因此不需要使用synchronized。如果按钮闪烁逻辑涉及后台线程操作共享数据,才需要针对共享资源(比如存储罗马音/片假名的列表)加锁,但你的场景中所有UI更新都应放在主线程完成,无需额外锁机制。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:42:31