【问题标题】:Initializing a thread in a static block?在静态块中初始化线程?
【发布时间】:2013-04-19 01:50:22
【问题描述】:
如果我在静态块中启动一个线程。 jvm 会在加载类之前等待线程完成吗?
static {
System.out.println("static block");
DataRetrievalThread t = new DataRetrievalThread();
t.run();
}
我尝试这样做的原因是
我想从服务器检索数据,但获取它的时间太长了。因此,为了持久化我想要检索的数据并将其存储在一个文件中,这样当客户端要求它时 - 它不需要调用服务器来获取信息。
【问题讨论】:
标签:
java
multithreading
static
jvm
【解决方案1】:
如果我在静态块中启动一个线程。 jvm 会在加载类之前等待线程完成吗?
呃。是的,不是的,不是的。
首先,您的代码没有派生线程。因此,正如它所写的那样,它将支持类的构造,尽管从技术上讲,该类在static 部分运行之前已“加载”。那是因为你在当前主线程中直接执行run() 方法。如果你想分叉线程,那么你应该调用t.start();。
如果你真的用t.start() fork 线程,那么不,线程将在后台运行,不会阻止类初始化。
你真的不应该做这样的事情。这是一个非常糟糕的模式。如果您解释了您要完成的工作,我们应该能够真正提供帮助。
如果您尝试将数据预加载到您的程序中,那么您应该尽早在 main() 中运行加载部分,并且不要将其停放在类中的 static 初始化程序中。但是如果你在主线程中运行它,阻止程序,我不明白为什么这比按需发出请求更快。
要考虑的一件事是分叉(使用t.start())一个后台线程来加载数据,然后拥有一个保存数据的类。如果线程及时完成,那么它将预先加载数据。当程序需要数据时,它应该调用类来获取它。如果线程还没有完成它可以做一个countDownLatch.await()。当线程完成下载时,它可以执行countDownLatch.countDown()。所以你会得到一些并行性。
类似:
public class DataLoader {
private volatile Stuff data;
private final CountDownLatch latch = new CountDownLatch(1);
// start the thread, called early in main()
public void init() {
// you pass in this so it can call setData
DataRetrievalThread t = new DataRetrievalThread(this);
t.start();
}
// called from the DataRetrievalThread
public void setData(Stuff data) {
this.data = data;
latch.countDown();
}
public Stuff getData() {
if (data == null) {
latch.await();
}
return data;
}
}
【解决方案2】:
使用run(),您在当前线程中执行该方法,因此之后该类将完成加载。您需要调用start() 在新线程中运行该方法。