[英]Need some clarification on Java threads: start() and run()
According to the StackOverflow answers, start()
creates a thread and executes the code in this new thread and run()
executes the code in the current thread without creating any - as if it was a Runnable
根据StackOverflow的答案, start()
创建一个线程并在此新线程中执行代码, run()
在当前线程中执行该代码而不创建任何代码-好像它是Runnable
But the docs, if I understood them properly, say that start()
initializes a new thread an then, if you want to re-execute your code in the same thread, you call run()
但是文档,如果我能正确理解它们,则说start()
初始化了一个新线程,然后,如果要在同一线程中重新执行代码,则调用run()
Which one is right? 哪一个是对的?
UPD UPD
Okay, looks like calling run()
manually is not a good practice and is at least useless. 好的,看起来手动调用run()
并不是一种好习惯,并且至少没有用。 Are there some good ways to call the code in run()
? 有一些好的方法可以在run()
调用代码吗? Say, I have a relatively slow action that is required frequently, one instance at a time - what then? 说,我有一个相对缓慢的动作,经常需要一次,一次实例-那么该怎么办?
As quoted, neither of them is right. 引,它们都不是正确的。
start
doesn't create or initialize a thread. start
不会创建或初始化线程。 It starts a thread. 它启动一个线程。 From the documentation : 从文档中 :
Causes this thread to begin execution; 使该线程开始执行; the Java Virtual Machine calls the run method of this thread. Java虚拟机将调用此线程的run方法。
The thread is created and initialized by calling the Thread
constructor, which naturally you have to do prior to calling start
. 线程是通过调用Thread
构造函数创建和初始化的,这自然是您必须在调用start
之前完成的。 (That's the "external myth," anyway; I'd have to check the JVM spec, but I suspect it would probably be valid for a JVM to defer actual creation of the OS thread until/unless you called start
.) (这就是“外部的神话,”无论如何,我得检查JVM规范,但我怀疑这很可能是有效的JVM推迟实际创建操作系统的线程,直到/除非你叫的start
。)
In the normal case, you never call the run
method of a Thread
instance directly. 在正常情况下,您永远不会直接调用Thread
实例的run
方法。 Instead, you start the thread via start
and the JVM schedules a call to run
on the actual thread assigned to that Thread
instance. 取而代之的是,您通过start
启动线程,并且JVM安排了一个调用,以在分配给该Thread
实例的实际线程上run
。 If you call run
directly, it gets called on the thread you're using to do that, which probably isn't the one assigned to the Thread
instance. 如果直接调用run
,它将在您正在使用的线程上被调用,这可能不是分配给Thread
实例的Thread
。
You may find the Java concurrency tutorial useful. 您可能会发现Java并发教程很有用。
Re your comment below: 在下面重新发表您的评论:
And how to re-execute the code in
run()
? 以及如何重新执行run()
的代码? Restart the thread or have some infinite loop with aboolean
value controlling the execution? 重新启动线程还是通过boolean
值控制执行有一些无限循环?
The latter, but not an infinite loop, a loop with a termination condition. 后者(但不是无限循环)是具有终止条件的循环。 From the start
documentation: 从start
文档:
It is never legal to start a thread more than once. 一次启动一个线程永远是不合法的。 In particular, a thread may not be restarted once it has completed execution. 特别是,线程一旦完成执行就可能不会重新启动。
So once run
returns, that's it, you can't keep using the thread. 因此,一旦run
返回,就可以继续使用线程。 Instead, you have the thread not return from run
until its work is done. 取而代之的是,线程必须等到其工作完成后才能从run
返回。 If you want to keep it around waiting for work, it should wait on a semaphore of some kind that you can signal from outside the thread, to wake it up to do some work. 如果您想让它一直等待工作,它应该等待某种信号量,您可以从线程外部发出信号,以唤醒它来做一些工作。
A subsection of the tutorial above talks about one way to do that with Guarded Blocks using wait
and notify
/ notifyAll
. 上面的教程的一个小节讨论了使用wait
和notify
/ notifyAll
来使用Guarded Blocks的一种方法。
Here's a simple example where every call to System.out.println
prints the name of the thread on which the call was made so you can see which thread does what: 这是一个简单的示例,其中对System.out.println
每次调用都将打印在其上进行调用的线程的名称,以便您可以看到哪个线程在做什么:
class Example
{
public static void main (String[] args) throws java.lang.Exception
{
Thread t= new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": Running run");
}
});
System.out.println(Thread.currentThread().getName() + ": Running main");
System.out.println(Thread.currentThread().getName() + ": Calling t.start()");
t.start();
System.out.println(Thread.currentThread().getName() + ": Calling t.join() to wait for thread exit");
try {
t.join();
} catch (InterruptedException ie) {
System.out.println(Thread.currentThread().getName() + ": Calling got InterruptedException");
}
System.out.println(Thread.currentThread().getName() + ": Program complete");
}
}
Example output: 输出示例:
main: Running main main: Calling t.start() main: Calling t.join() to wait for thread exit Thread-0: Running run main: Program complete
Note that our main thread just called start
; 请注意,我们的主线程仅称为start
; then the JVM set things up so that run
would be called on the thread we'd created. 然后JVM进行设置,以便在我们创建的线程上调用run
。
Your confusion probably comes from the ambigous use of the terms thread , create and initialize . 您的困惑可能是由于术语“ 线程” ,“ 创建”和“ 初始化”的使用过多而引起的。 Without specifying what they exactly address its easy to misunderstand, because there are multiple concepts that the term thread is used to describe. 由于没有使用术语“ 线程”来描述多个概念,因此没有明确说明它们的确切含义很容易造成误解。
On one hand, there is the Thread object (that is created through new Thread(...) constructor). 一方面,存在Thread对象(通过新的Thread(...)构造函数创建)。 Thats not the thread in terms of actually executing anything. 那不是实际执行任何事情的线程。 Its just a facade for the threading mechanism that implements a standardized API to interact with the OS/VM. 它只是实现了一个标准的API与OS / VM交互的线程机制的一个门面 。
Just creating a Thread instance is basically not any different from creating any other java object. 基本上,仅创建Thread实例与创建任何其他Java对象没有什么不同 。 Nothing happens yet that has anything to do with actually adding a thread to the OS thread scheduler. 尚未发生任何与将线程实际添加到OS线程调度程序有关的事情。
The thread on the OS side is actually created in a (private) native method start0(), the start() method performs some sanity checking, then calls start0() to actually create an OS-Level thread. 操作系统端的线程实际上是在(私有)本机方法start0()中创建的,start()方法执行了一些健全性检查,然后调用start0()来实际创建OS级线程。
So the general order of actions is: 因此,一般的操作顺序为:
Here is the main difference between start() and run(): 这是start()和run()之间的主要区别:
Thread#start : when program calls start() method the Java Virtual Machine calls the run method of this thread. Thread#start :当程序调用start()方法时,Java虚拟机将调用此线程的run方法。
Thread#run : If you call run() method directly code inside run() will execute on current Thread. Thread#run :如果直接调用run()方法,则run()内部的代码将在当前Thread上执行。
if I understood them properly, say that start() initializes a new thread an then, if you want to re-execute your code in the same thread, you call run() 如果我正确理解它们,则说start()初始化一个新线程,然后,如果要在同一线程中重新执行代码,则调用run()
This is incorrect. 这是不正确的。 You need to understand that every Java program begins it's execution with the main thread. 您需要了解,每个Java程序都是从主线程开始执行的。 In other words, when you run a Java program that has a main
method (eg java MyProgram), a new execution stack is created with the main
method at the bottom of this stack. 换句话说,当您运行具有main
方法的Java程序(例如java MyProgram)时,将创建一个新的执行堆栈,并且main
方法位于该堆栈的底部。
If a program creates a Thread
instance in the main
method and calls the start
method on the thread instance, a new execution stack will be created with the run
method at the bottom of the stack. 如果程序在main
方法中创建一个Thread
实例并在该线程实例上调用start
方法,则将创建一个新的执行堆栈,并在堆栈底部使用run
方法。 You will now have two execution stacks. 您现在将具有两个执行堆栈。 One with the main
method at the bottom of the stack and the other with the run
method at the bottom of the stack. 一种是在堆栈底部使用main
方法,另一种是在堆栈底部使用run
方法。 These two stacks can complete their execution in parallel. 这两个堆栈可以并行完成其执行。
On the other hand, If you call run
on a thread instance in the main
method instead, it will simply be called in the same execution stack as the main
method. 另一方面,如果改为在main
方法中调用线程实例上的run
,则它将简单地在与main
方法相同的执行堆栈中调用。 A new execution stack will not be created. 将不会创建新的执行堆栈。 Therefore, calling run
on a thread instance is as good as calling any other method on any other object and has no special meaning. 因此,在线程实例上调用run
与在任何其他对象上调用任何其他方法一样好,并且没有特殊含义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.