【问题标题】:synchronized threads not blocking each other同步线程不会互相阻塞
【发布时间】:2016-04-29 17:16:12
【问题描述】:

我不想用另一个相同的问题来填满董事会,但我阅读了大约 15 个解决方案,没有人遇到完全相同的问题。这是我正在查看的代码:

private AgentModel agent;
private UserModel user;
private int type;

public AgentThread(AgentModel agent, UserModel user, int type) {
    this.agent = agent;
    this.user = user;
    this.type = type;
}

public void start() throws InterruptedException {
    agent.setT(new Thread(this, agent.getID()));
    agent.getT().start();
}

还有一点点:

public void run() {
    while (!agent.getT().isInterrupted()) {
        agent.nextOP();

        try {
            if (agent.getOPS() > 0) {
                agent.getT().sleep((long) (1000 / agent.getOPS()));
            } else {
                agent.getT().sleep(1000);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            agent.getT().interrupt();
        }
        synchronized (user) {
            agent.setState(agent.getT().getState().toString());
            // System.out.println("Operations Completed: " +
            // (1+agent.getOPCompleted()) );
            if (type == 3) {
                user.deposit(agent.getAmount(), Integer.valueOf(agent.getID()));
            }
            if (type == 4) {
                user.withdraw(agent.getAmount(), Integer.valueOf(agent.getID()));
            }
        }
    }
}

代理对象包含一个在 AgentThread 启动方法中启动的线程。 AgentThread 对象同时接受代理和用户以及它们各自类的实例。

我的问题如下:我将锁设置为 UserModel 类“用户”的实例。线程应该根据它们的代理类型进行存款或取款。

当我执行agent.getT().getState() 时,无论我创建了多少个 AgentThread 实例,它总是返回 RUNNABLE。每个 AgentThread 都被赋予一个新代理和一个新线程,但具有相同的用户对象。似乎线程从不相互阻塞。

我知道它们正在影响同一个用户实例,因为我可以输出我的侦听器检测到的更改,它反映了所有正在运行的线程及其与该用户实例的交互。

每次启动线程时,它都会进入一个“无限”循环,其中用户实例有存款或取款。这些操作每 x 秒发生一次。

【问题讨论】:

  • 您没有向我们展示很多代码,但出于好奇,您希望线程在任何一次通过 synchronized 块时花费多少时间?它可能只有几微秒。你说,“不管我创建了多少个AgentThread 实例”,但那是多少个实例?他们多久进入一次synchronized 区块?而且,您的程序多久询问一次线程的状态?我真正想说的是,您有什么理由认为该锁会有如此多的争用,以至于您可能会注意到它?
  • @james large 我有 4 个实例同时运行,所有实例都很快进入块,程序每次通过块时都会询问线程状态
  • @mastov 我如何检测线程是否在检查其状态之外被阻塞?
  • @mastov 我明白了,所以同步块很可能工作正常,我只是无法通过线程的 state 属性来确定...真可惜
  • @jameslarge 好吧,我并不希望他们达到阻塞状态,但在我看来,至少在某个时间点他们会阻塞。然而,当你把它放在透视图上时,我想他们永远不会真正互相阻挡,或者至少我注意到它发生得如此之快的机会非常低。

标签: java multithreading synchronized


【解决方案1】:

您的线程仅将 User 对象锁定足够长的时间,以便以可能数百毫秒的间隔执行 deposit() 或 withdraw() 操作。除非 deposit() 或withdraw() 依赖于高延迟的外部资源,否则它们可能会在几分之一微秒内执行,这对于数千行代码来说已经足够了。因此,您在线程锁定用户对象的状态下捕获系统的机会可能小于 100,000 分之一。此外,要阻塞另一个线程,它也需要尝试执行 deposit() 或withdraw() 操作。考虑到您可能的参数,这种碰撞的可能性不到百万分之一,这很可能解释了为什么您从未见过它。

【讨论】:

    【解决方案2】:

    当我执行 agent.getT().getState() 时,无论我创建了多少个 AgentThread 实例,它总是返回 RUNNABLE。

    没错。这是因为您从线程本身内部调用agent.getT().getState()。该线程将始终将自身视为RUNNABLE。当它被阻塞或等待时,它不看。

    似乎线程从不相互阻塞。

    不,当我阅读代码时,如果他们在同一个 User 对象上工作,它们肯定会相互阻塞。但是,您永远不会从另一个线程调用agent.getT().getState(),因此它可以看到BLOCKEDWAITING 状态。

    从外部查看线程的一种方法是通过turning on JMX 并使用jconsole。如果您转到线程选项卡,您应该能够看到工作线程上的“总阻塞”和“总等待”计数增加。

    每次启动线程时,它都会进入一个“无限”循环,其中用户实例有存款或取款。这些操作每 x 秒发生一次。

    我想这就是你所期望的。

    【讨论】:

      猜你喜欢
      • 2017-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多