Java 为什么我要签入一个Runnable,它的线程不是null?

Java 为什么我要签入一个Runnable,它的线程不是null?,java,runnable,Java,Runnable,在我接管的一个项目中,我发现了这样的代码。我不确定if条件应该实现什么。如果Runnable正在运行,它会在检查为null的线程中执行此操作。所以情况总是这样,对吗 public class Outer { Thread m_thread = null; public Outer() { Runnable runner = new Runnable() { public void run()

在我接管的一个项目中,我发现了这样的代码。我不确定if条件应该实现什么。如果Runnable正在运行,它会在检查为
null
的线程中执行此操作。所以情况总是这样,对吗

public class Outer 
{
    Thread m_thread = null;

    public Outer() 
    {
         Runnable runner = new Runnable()
         {
             public void run()
             {
                 if ( m_thread != null )
                     do_stuff();
             }
         };

         m_thread = new Thread(runner);
         m_thread.start();
    }
}

实际上还有另一种方法,它将
m_-thread
设置为
null
,但是由于runnable中没有循环,这会有区别吗
do_stuff()
不访问
m_thread

,因为
m_thread
未标记
volatile
或由任何其他内存屏障操作保护,所以当运行
Runnable
时,可能会观察到
m_thread
null
。如果
do_stuff()
要求对
m_thread
进行非空引用,则代码将失败

查看Shipilev的文章,了解Java中的安全发布习惯用法。简言之:

有几种简单的方法可以实现安全发布:

  • 通过正确锁定的字段交换参考(JLS 17.4.5)
  • 使用静态初始化器初始化存储(JLS 12.4)
  • 通过volatile字段(JLS 17.4.5)交换引用,或者根据本规则,通过AtomicX类交换引用
  • 将值初始化为最终字段(JLS 17.5)

由于
m_线程
未标记为
volatile
或由任何其他内存屏障操作保护,因此当
Runnable
运行时,它可能会观察到
m_线程
null
。如果
do_stuff()
要求对
m_thread
进行非空引用,则代码将失败

查看Shipilev的文章,了解Java中的安全发布习惯用法。简言之:

有几种简单的方法可以实现安全发布:

  • 通过正确锁定的字段交换参考(JLS 17.4.5)
  • 使用静态初始化器初始化存储(JLS 12.4)
  • 通过volatile字段(JLS 17.4.5)交换引用,或者根据本规则,通过AtomicX类交换引用
  • 将值初始化为最终字段(JLS 17.5)

简单地说:这没有任何意义。在Java中执行一行代码时,某个线程正在运行它

除非您开始实现自己的线程跟踪,否则您的代码正在运行的事实。。。告诉它某个线程正在运行它

这里显示的代码A)违反Java命名约定,B)违反Java中的“常识”

您可以看到,您仍然可以编写代码,首先初始化
m_thread
字段,然后直接从“主”线程调用
runner.run()
。run方法将发现该字段不为null,并调用
doStuff()
。如果有的话,您可以检查
Thread.getCurrentThread()
是否返回比“主”线程更的内容

例如:

class Outer {
  private Thread mainThread;

  public Outer() 
  {
     mainThread = Thread.getCurrentThread();

     Runnable runner = new Runnable()
     {
         public void run()
         {
             if ( Thread.getCurrentThread() != mainThread )
                 do_stuff();
         }
     };

     m_thread = new Thread(runner);
     m_thread.start();
}

(我没有通过编译器运行上面的内容,这是一个“类似伪代码”的示例,不一定100%正确)

简单地说:这没有任何意义。在Java中执行一行代码时,某个线程正在运行它

除非您开始实现自己的线程跟踪,否则您的代码正在运行的事实。。。告诉它某个线程正在运行它

这里显示的代码A)违反Java命名约定,B)违反Java中的“常识”

您可以看到,您仍然可以编写代码,首先初始化
m_thread
字段,然后直接从“主”线程调用
runner.run()
。run方法将发现该字段不为null,并调用
doStuff()
。如果有的话,您可以检查
Thread.getCurrentThread()
是否返回比“主”线程更的内容

例如:

class Outer {
  private Thread mainThread;

  public Outer() 
  {
     mainThread = Thread.getCurrentThread();

     Runnable runner = new Runnable()
     {
         public void run()
         {
             if ( Thread.getCurrentThread() != mainThread )
                 do_stuff();
         }
     };

     m_thread = new Thread(runner);
     m_thread.start();
}

(我没有通过编译器运行上面的内容,这是一个“类似伪代码”的示例,不一定100%正确)

你没有。20年前有一种时尚,我认为可能起源于一本杂志,即
run()
方法循环
,而(Thread.currentThread()!=null)
。它在当时和现在都是毫无意义的,即使是在代码中稍微重新表达出来。

你没有。20年前有一种时尚,我认为可能起源于一本杂志,即
run()
方法循环
,而(Thread.currentThread()!=null)
。它在当时毫无意义,现在也毫无意义,即使在代码中稍微重新表达。

不管怎样,
运行程序
新线程(运行程序)
中使用,也毫无意义,此
线程
将永远不会为
…是否有其他地方的代码将
m_Thread
设置为空?这看起来像是简化了代码:可能有一些相关的细节被忽略了。创建线程充当了写/读屏障。如果您设置了一个值,则该值对于该线程在此之后启动的任何线程都是可见的。不管怎样,
runner
新线程(runner)
中使用都没有意义,此
线程
将永远不会为
…是否有其他地方的代码将
m_Thread
设置为空?这看起来像是简化了代码:可能有一些相关的细节被忽略了。创建线程充当了写/读屏障。如果您设置了一个值,该值将对该线程在此之后启动的任何线程可见。创建线程是一个读/写内存屏障,因此代码不会失败。创建线程是一个读/写内存屏障,因此代码不会失败。