我想问一下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的流行语也会非常有用
答案 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完成他的工作?
因为线程是专门制作的,所以不要互相等待。 如果您希望一个线程等到另一个线程完成,请使用synchronized方法或阻止。
Singleton方法是可重入的,因为实际代码在类对象中。
即使有两个非单例对象,类中仍然只有一个代码实例。
对我来说唯一的解释是,JVM会以某种方式将字节代码从堆复制到每个线程
这是错误的
BTW:实际上没有&#34;同时&#34;线程切换之间只需几纳秒......答案 3 :(得分:0)
我可以帮助您处理最后几段 -
代码只有一个副本,但两个线程都可以同时运行它。可能两个cpu核心正在同时运行代码,但每个CPU都指向不同的数据,因此完全相同的代码可能对不同的数据进行操作。
实际上,一个CPU可能有数据评估为&#34; true&#34;另一个人可能会评价为&#34; false&#34;所以if()语句会导致线程发散。
问题是没有足够的CPU,所以我们有办法保存和恢复单个CPU的状态,这样它就可以在一定程度上像多个CPU一样 - 每个虚拟CPU都是一个线程。
由于它们可以保存状态,因此单个CPU可以同时运行数千个线程(看似),每秒停止并重新启动它们数千次。
缺点是它只是代码的一个副本,但每个线程的数据不同。