当前位置: 首页 > 知识库问答 >
问题:

为什么这段代码不抛出NullPointerException?

徐帅
2023-03-14

我想了解为什么一段代码不会抛出NullPointerException。

请考虑以下代码:

public class Agent {
  public List files = new ArrayList();

  public void deliver() {
    if( files != null && files.iterator().hasNext() ) {
      File file = (File)files.iterator().next();
    }

    files = new ArrayList();
  }
}

deliver方法被重复调用,同时以下代码在单独的线程中运行:

  public void run() {
    agent.files = null;
  }

只有一个agent实例。

从不引发NullPointerException。

但是,当Deliver方法暂停时,即使暂停0毫秒,也会按预期引发NullPointerException:

  public void deliver() {
    if( files != null ) {
      Thread.currentThread().sleep( 0 );

      if( files.iterator().hasNext() ) {
        File file = (File)files.iterator().next();
      }
    }

    files = new ArrayList();
  }

我的理解是,在理论上,在检查文件==null和调用文件.Iterator().hasNext()之间存在竞争条件。在实践中,如果不引入暂停(即从后续方法调用中拆分空检查),我就无法触发竞态条件。

为什么第一个deliver方法在相同语句中合并了null检查和用法时不抛出异常?

共有1个答案

堵茂勋
2023-03-14

两件事:

>

  • thread.sleep(0)仍然停止执行(可能超过0毫秒)。基本上,即使是0睡眠也会导致线程上的执行短暂停止,然后重新启动。这给了另一个线程一个运行和完成的机会,这就是为什么您能够触发竞态条件。

    文件应该是volatile,否则允许JVM以这样一种方式进行优化,即您可能永远不会注意到它在改变值,因为它认为它不需要维护线程之间的一致性。

  •  类似资料:
    • 问题内容: 考虑以下Java源代码: 该是。 为什么该语句有时会抛出? 谢谢。 问题答案: 线程安全 如果您的代码是多线程的,则有可能。例如: 如果在语句执行之后(但在循环之前)立即将另一个线程设置为,则您将获得一个。通过使用访问器(与延迟初始化结合使用)可以避免这种情况。 另外,如其他人所提到的,如果可能,请避免使用有利于泛型的此类循环构造。有关详细信息,请参见其他答案。 配件提供保护 如果始终

    • 我有一些流处理代码,它接受一个单词流并对它们执行一些操作,然后将它们简化为一个,其中包含单词作为键,单词的出现次数作为值。为了代码的简洁性,我使用了jOOL库的类,其中包含许多有用的快捷方法。 类型中的方法不适用于参数 type未定义此处适用的 为什么的行为与有任何不同,我(也许是天真地)认为它是直接等效的,为什么编译器在使用它时不能处理它? (是的,我知道我可以通过将以前的应用程序移到操作中来删

    • 这段代码是我用Java Swing制作的Tic-Tac-Toe程序的一部分。为什么在添加用于添加按钮的for语句时返回NullPointerException?

    • 在方法或类范围内,下面的行编译(带有警告): 在类作用域中,变量获取其默认值,以下给出未定义引用错误: 这难道不是第一个应该以相同的未定义引用错误结束吗?或者第二行应该编译?或者我错过了什么?

    • 如果你注释掉的内部循环,它会抛出,这显然是因为我们对集合做了更改。 如果取消注释,为什么这个循环允许我们添加这两项?运行它需要一段时间(在奔腾CPU上)大约半分钟,但它不会抛出,有趣的是,它输出: 这有点出乎意料,但它表明我们可以改变,它实际上改变了集合。知道为什么会发生这种行为吗?