JVM如何同时处理spring单例代码?

时间:2018-06-12 21:45:28

标签: java concurrency jvm

我想问一下Spring Singleton内部如何在并发软件中运行。请使用您知道的尽可能多的详细信息。我想知道JVM如何解决这个问题。

我在这里找到类似的问题 - 然而,这个问题涉及两个单独的线程调用的两个单独的方法 - 这里我有一个方法和两个线程

@Component 
public class SpringSingleton {

  public void justWait(){
     try {
        Thread.sleep(5000); 
     }
     catch(InterruptedException ex) {}
  } 
} 

@Component
public class StartClass {

   @Autowired 
   private SpringSingleton singleton; 

   public void runAfterAppStart(){
     for(int i=0; i<=1; i++){ 
         CompletableFuture.runAsync(() ->  singleton.justWait());
     }
   }
}

运行这些代码后,您将看到两个线程几乎同时结束。

怎么可能?为什么Thread2不必等到Thread1完成他的工作?

据我了解整个流程,SpringSingleton类的实例将放在JVM堆上,然后在堆栈上Java将放置两个线程(Thread1,Thread2)。每个线程都包含对Spring Singleton类的自有(独立)引用 - 现在......

Thread1将使用他的引用来执行方法“justWait”。这些方法显然是处理器的一些指令。因此,如果这些指令当前是进程 - Thread2如何能够调用它们? 对我来说唯一的解释是,JVM会以某种方式将字节代码从堆复制到每个线程 - 然后每个方面都很清楚 - 但它确实发生在这里?

感谢您解释该问题。即使是我可以google的流行语也会非常有用

4 个答案:

答案 0 :(得分:0)

您的问题与Spring Singleton实施无关。

有3个主题。一个主线程和2个CompletableFuture线程。主线程创建可完成的期货,完成它的工作和应用程序退出。它不会等待CompletableFuture完成。

您可以通过在循环后添加额外的Thread.sleep(10000)来检查这一点,例如:

    public void runAfterAppStart(){
     for(int i=0; i<=1; i++){ 
         CompletableFuture.runAsync(() ->  singleton.justWait());
     }
     // Hold main thread for the CompletableFuture to complete.
     Thread.sleep(10000);
   }

答案 1 :(得分:0)

  

怎么可能?为什么Thread2不必等到Thread1完成他的工作?

因为您没有进行任何同步。

  

对我来说唯一的解释是,JVM会以某种方式将字节代码从堆复制到每个线程 - 然后每个方面都很清楚 - 但它确实发生在这里?

你混淆了两件事:实例变量和字节码。字节码是编译的Java代码,只存在一次,而不是堆。实例变量是在堆上创建的,但每个线程都有自己的set。

但是,在此示例中,没有任何实例变量。所以每个线程只运行相同的字节码。没有必要等待,因为字节码在加载后不会改变。

答案 2 :(得分:0)

  

为什么Thread2不必等到Thread1完成他的工作?

  1. 因为线程是专门制作的,所以不要互相等待。 如果您希望一个线程等到另一个线程完成,请使用synchronized方法或阻止。

  2. Singleton方法是可重入的,因为实际代码在类对象中。

  3. 即使有两个非单例对象,类中仍然只有一个代码实例。

    1. 当object(bean)是一个单例时,它意味着该类只有一个实例,并为其数据 - 实例变量分配了内存。
    2.   

      对我来说唯一的解释是,JVM会以某种方式将字节代码从堆复制到每个线程

      这是错误的

      BTW:实际上没有&#34;同时&#34;线程切换之间只需几纳秒......

答案 3 :(得分:0)

我可以帮助您处理最后几段 -

代码只有一个副本,但两个线程都可以同时运行它。可能两个cpu核心正在同时运行代码,但每个CPU都指向不同的数据,因此完全相同的代码可能对不同的数据进行操作。

实际上,一个CPU可能有数据评估为&#34; true&#34;另一个人可能会评价为&#34; false&#34;所以if()语句会导致线程发散。

问题是没有足够的CPU,所以我们有办法保存和恢复单个CPU的状态,这样它就可以在一定程度上像多个CPU一样 - 每个虚拟CPU都是一个线程。

由于它们可以保存状态,因此单个CPU可以同时运行数千个线程(看似),每秒停止并重新启动它们数千次。

缺点是它只是代码的一个副本,但每个线程的数据不同。