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

Java同步机制无法实现互斥的问题咨询

问题分析与解决方案

咱们先拆解下核心问题:你提到多个Node实例调用Receive类的synchronized方法rcv()时,输出还是混杂,说明互斥锁根本没生效。最常见的原因是——你的多个Node可能各自持有独立的Receive实例,而synchronized实例方法的锁是当前对象实例,不是类本身。也就是说,每个Receive实例的锁是分开的,线程们各拿各的锁,自然不会互斥。

先确认问题根源

先对照下你的代码是不是类似这种情况:

public class Receive {
    public synchronized void rcv() {
        // 输出逻辑,比如打印当前Node的信息
        System.out.println("Node " + Thread.currentThread().getName() + " is receiving...");
        // 模拟耗时操作,放大混杂情况
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Node " + Thread.currentThread().getName() + " finished receiving");
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            // 每个Node都new一个独立的Receive实例
            new Node(new Receive()).start();
        }
    }
}

class Node extends Thread {
    private Receive receive;

    public Node(Receive receive) {
        this.receive = receive;
    }

    @Override
    public void run() {
        receive.rcv();
    }
}

如果是这样,问题就很明确了:每个Node对应的Receive实例都不一样,synchronized void rcv()的锁是各自的Receive对象,线程之间根本不会竞争同一把锁,所以输出会混杂。

两种靠谱的解决方案

根据你的业务需求,选下面其中一种就行:

方法1:让所有Node共享同一个Receive实例

既然synchronized实例方法的锁是对象本身,那让所有Node共用一个Receive对象,所有线程就会竞争同一把锁:

public class Main {
    public static void main(String[] args) {
        // 只创建一个Receive实例,传给所有Node
        Receive sharedReceive = new Receive();
        for (int i = 0; i < 3; i++) {
            new Node(sharedReceive, "Node-" + i).start();
        }
    }
}

class Node extends Thread {
    private Receive receive;

    public Node(Receive receive, String name) {
        super(name);
        this.receive = receive;
    }

    @Override
    public void run() {
        receive.rcv();
    }
}

方法2:使用类锁替代对象锁

如果你不想共享Receive实例,那可以把rcv()改成静态同步方法,或者在方法内部用类锁——类锁是绑定在Receive.class对象上的,不管有多少Receive实例,所有线程都会竞争这同一把锁:

// 方案2.1:静态同步方法
public class Receive {
    public static synchronized void rcv() {
        System.out.println("Node " + Thread.currentThread().getName() + " is receiving...");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Node " + Thread.currentThread().getName() + " finished receiving");
    }
}

// 方案2.2:实例方法内部用类锁
public class Receive {
    public void rcv() {
        synchronized (Receive.class) {
            System.out.println("Node " + Thread.currentThread().getName() + " is receiving...");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Node " + Thread.currentThread().getName() + " finished receiving");
        }
    }
}

验证效果

不管用哪种方法,运行后你会看到每个Node的输出都是完整的:先打印某个Node的"is receiving...",等它执行完耗时操作,再打印"finished receiving",才会轮到下一个Node,不会再出现输出混杂的情况。

最后提个小提醒:如果Receive类里有其他非线程安全的成员变量,也要确保这些变量的访问都在锁的保护下,不然还是可能出现线程安全问题哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:43:22