任何单线程程序如何成为有效的多线程程序?

时间:2017-03-08 15:04:16

标签: java multithreading concurrency thread-safety

我正在阅读这本书" Java Concurrency In Practice"。在第二章中,我阅读了声明

  

任何单线程程序也是有效的多线程程序

我无法理解这句话。

请分享您的想法,以便清除我的困惑。提前谢谢。

3 个答案:

答案 0 :(得分:3)

请注意,该语句并不意味着任何正确的单线程程序也是正确的多线程程序,作者只是声明可以转换任何单线程程序在多线程环境中执行。 / p>

但是,如果程序在单线程环境中已经不是正确,那么在更复杂的多线程环境中它可能不正确。

从书中可以看出:

  

由于任何单线程程序也是有效的多线程程序   程序,如果它甚至不正确,它就不能是线程安全的   单线程环境。

     

如果对象正确实现,则不会执行任何操作调用   公共方法和公共领域的读取或写入应该能够   违反任何不变量或后置条件。没有一套   在a的实例上顺序或同时执行的操作   线程安全类可能导致实例处于无效状态。

而且:

  

如果松散使用"正确性"在这里困扰你,你可能更喜欢   把线程安全类看作是一个不再破坏的类   并发环境比单线程环境。

@yshavit 在您考虑多线程正确性之前,请确保您至少具有单线程正确性。

答案 1 :(得分:2)

  

任何单线程程序也是有效的多线程程序

这基本上意味着任何单线程程序都可以在多线程上下文中使用。以下面的代码为例:

class A {
    public void doSomething() {  }
}

如果我们孤立地考虑上面的类,它显然是一个单线程程序;但是,同样的程序也可以在多线程上下文中使用:

Thread thread1 = new Thread(new Runnable() {  public void run() { A a = new A(); a.doSomething(); } }).start();
Thread thread2 = new Thread(new Runnable() {  public void run() { A a = new A(); a.doSomething(); } }).start();

谈论书中你没有提出但是值得讨论的具体相关段落:

  

没有按顺序或同时执行的操作集   线程安全类的实例可以导致实例在   无效状态

让我们在课堂上添加一些状态:

class A {
    int iCantBeNegative = 10;
    public void doSomething() { --icantBeNegative;  }
}

程序员的期望是iCantBeNegative永远不应该小于零,然而,他们没有采取任何措施来强制执行此要求。从预期的角度来看,这个程序在单线程上下文中主要是不正确的(iCantBeNegatvie如果doSomething被连续11次或更多次调用将是< 0),这是最多的在多线程环境中肯定是不正确的。

答案 2 :(得分:1)

  

"任何单线程程序也是一个有效的多线程程序"

在没有阅读本书和阅读本节的情况下,在JVM中运行时,单线程应用程序实际上是多线程的有很多种方式。在JVM启动时,有许多JVM特定的线程被分叉。它们包括gc线程,终结器,JMX线程(如果启用)等。这些线程在后台运行,以帮助JVM高效运行。

例如,在我的OSX框中,默认情况下会分叉以下线程:

  • 参考处理程序
  • 终结
  • 信号调度员
  • 附加监听器
  • 如果启用了JMX,则会有许多RMI和JMX线程

此外,当运行用户应用程序代码的主线程遇到synchronized块或访问库或JDK中的volatile字段时,主线程会经历内存障碍,获取和释放锁等就像多线程应用程序一样。这可能是作者引用的内容。

最后,重要的是要认识到“重入”这个术语"是在线程概念被发明之前创建的。由于递归方法或中断处理程序,代码需要正确编写为可重入,这意味着代码可以输入两次,即使它永远不是多个"线程"。在上下文切换,交换/输出,缓存等等之前,需要编写适当的可重入代码。是的,我在这里显示我的年龄。