关于Thread类中的start()方法和run()方法

2019-03-25 13:32|来源: 网路

引用

public void start()
Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
Throws:
IllegalThreadStateException - if the thread was already started.

public void run()
If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns.
Subclasses of Thread should override this method.
Specified by:
run in interface Runnable

上面是Thread类中Start()方法与run()方法的定义。
现有自定义的类如下:
public class Test2 {
	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {			
			@Override
			public void run() {
				System.out.println("in runnable() run().");
			}			
		});
		Thread t2 =new MyThread();
		t1.start();
		t2.start();
	}	
	static class MyThread extends Thread {
		@Override
		public void run() {
			System.out.println("in MyThread() run().");
		}
	}
}

由于t2并没有指定target,即没有这样定义
Thread t2 = new Thread(new MyThread());
所以根据API中run()方法的定义,t2.start()方法的调用应该没有调用MyThread的run()方法。
Thread类的run() 源代码如下:
public void run() {
	if (target != null) {
	    target.run();
	}
    }

Thread类无参构造函数
public Thread() {
	init(null, null, "Thread-" + nextThreadNum(), 0);
    }
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
	Thread parent = currentThread();
	SecurityManager security = System.getSecurityManager();
	if (g == null) {
	    /* Determine if it's an applet or not */	    
	    /* If there is a security manager, ask the security manager
	       what to do. */
	    if (security != null) {
		g = security.getThreadGroup();
	    }
	    /* If the security doesn't have a strong opinion of the matter
	       use the parent thread group. */
	    if (g == null) {
		g = parent.getThreadGroup();
	    }
	}
	/* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
	g.checkAccess();
	/*
	 * Do we have the required permissions?
	 */
	if (security != null) {
	    if (isCCLOverridden(getClass())) {
	        security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
	    }
	}
        g.addUnstarted();
	this.group = g;
	this.daemon = parent.isDaemon();
	this.priority = parent.getPriority();
	this.name = name.toCharArray();
	if (security == null || isCCLOverridden(parent.getClass()))
	    this.contextClassLoader = parent.getContextClassLoader();
	else
	    this.contextClassLoader = parent.contextClassLoader;
	this.inheritedAccessControlContext = AccessController.getContext();
	this.target = target;
	setPriority(priority);
        if (parent.inheritableThreadLocals != null)
	    this.inheritableThreadLocals =
		ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;
        /* Set thread ID */
        tid = nextThreadID();
    }

但是根据API中start()方法的说明,run()方法是由JVM调用的,这是不是矛盾了?
求解答,谢谢啦。

问题补充:首先,谢谢AngelAndAngel和chen_yongkai的回答。
Thread t3 = new Thread(new MyThread());

Thread t4 = new MyThread();

上面两种定义方式,t3.start()后,启动此线程,调用流程是MyThread类的run()方法。因为它们调用的构造器是
Thread(Runnable target)
,此时Thread类的target就等于new MyThread()这个对象,所以它会直接调用target.run()这个方法。

而t4.start()后,启动此线程是通过JVM调用的start0()方法,再调用的run()的一个流程。

这样理解正确吗?

问题补充:问题补充。
AngelAndAngel 写道
调用start的时候不是马上调用run方法,而是触动调用了run。
但是你要是自己调用也不是不行(不会有线程调用的效果而已,这样和普通方法就木有区别了),只是说线程得通过启动(start)来调用


问题补充:问题补充
chen_yongkai 写道
    public synchronized void start() {
        if (started)
            throw new IllegalThreadStateException();
        started = true;
        group.add(this);
        start0();
    }

    private native void start0();


在start0()方法中jvm调用run()方法,因为是native所以看不到源码。


问题补充:对头,我怎么木有想到呢~ 谢谢啦。
chen_yongkai 写道
    static class MyThread extends Thread {   
        @Override  
        public void run() {   
            System.out.println("in MyThread() run().");   
        }   
    }  

你已经覆盖了Thread 的run方法,就没有什么target的说法了
public void run() {   
    if (target != null) {   
        target.run();   
    }   
    }  

相关问答

更多
  • 看一下Thread类的源码,也许你就能搞清楚为身么文档里这样解释。 这是Thread类的run()方法的代码。一目了然如果target存在的话执行target的run()方法,否则什么也不做。这样我们可以推测(因为Thread 实际运行的方法start0 是native方法 我们看不到它的实现)也就是说Thread的run()方法总是先被调用的,然后调用taget(构造函数中的Runnable对象)的run()方法。 public void run() { if (target != null) { tar ...
  • 看一下Thread类的源码,也许你就能搞清楚为身么文档里这样解释。 这是Thread类的run()方法的代码。一目了然如果target存在的话执行target的run()方法,否则什么也不做。这样我们可以推测(因为Thread 实际运行的方法start0 是native方法 我们看不到它的实现)也就是说Thread的run()方法总是先被调用的,然后调用taget(构造函数中的Runnable对象)的run()方法。 public void run() { if (target != null) { tar ...
  • 这是python实现多线程时启动多线程的两种方法,如果是start方法,你需要实现一个函数,或者一个类,里面包含了一个可执行函数,然后通过start把函数名和其参数传进去就可以了; 如果使用run方法,那么你要定义一个类,并且继承Thread类实现软方法那么你可以这样启动:子类的对象.run()即可
  • Thread.start()方法启动一个新线程,此线程的入口点是run()方法。 如果直接调用run(),它将在同一个线程中执行。 考虑到调用Thread.start()将启动一个新的执行线程, run()方法可能会在执行主方法的其余部分之后调用(就像在本例中那样)。 改变你的主要方法来调用th1.start()并重复运行,你会看到有时会输出: EXTENDS RUN>> RUNNABLE RUN >> 有时会输出: RUNNABLE RUN >> EXTENDS RUN>> 取决于java如何选择安排 ...
  • 请仔细查看Thread类的run方法的实现,如下所示: public void run() { if (target != null) { target.run(); } } 因此,调用Thread的run方法会调用传递的Runnable的运行,在您的情况下,您在创建Thread t时传递了A的实例。 因此,调用super.run()调用Thread类的run方法,该方法又调用A的run方法(可运行或目标)。 See carefully the implemen ...
  • 我认为最好的做法是拥有两个独立的线程。 您可以(也可能应该)编写一个实现Runnable的新类,并在其中放置您的逻辑。 如果您必须实现两个业务逻辑之间的共同活动,则可以将此类用作两个“Runnables”的基类。 每个Runnable应该在一个单独的线程中生成。 你可以在这篇文章中找到Thread vs. Runnable非常好的推理: “implements Runnable”vs.“extends Thread” I think that the best course of action would ...
  • 您需要知道该线程可以具有不同的状态。 根据http://www.tutorialspoint.com/java/java_multithreading.htm有5个线程状态 新线程已创建并可以启动 runnable - 正在执行线程 等待 - 线程正在等待其他线程完成; 其他线程必须通过调用共享锁的notify方法来通知该线程它完成了 定时等待 - 类似于等待,但线程将在一段时间后自动停止等待,而不等待来自其他线程的信号 终止 - 线程完成其任务 run方法只包含线程工作时(当它处于可运行状态时)需要执行的 ...
  • 是的,线程将在执行方法时阻塞,因此它无法同时从套接字读取。 没有信息会丢失,传输只需要更长的时间,如果计算时间过长,您可以获得套接字超时。 如果您的方法需要很长时间才能运行,那么您应该在另一个工作线程中执行它。 我建议使用Executor 。 Yes, the thread will block while executing the method, so it can not read from the socket at the same time. No information will be los ...
  • 检查你的日志。 我的猜测是因为你试图从一个线程创建Toast而出现错误。 对于Toast命令以及影响ui的所有其他调用,应将其包装在runOnUiThread()中。 Check your log. My guess is that there is an error because you are trying to create a Toast from a thread. For the Toast command, and all other calls that affects the ui, y ...
  • 停止从Controller继承: controller = Controller() thread = threading.Thread(target=controller.run_forever) Stop inheriting from Controller: controller = Controller() thread = threading.Thread(target=controller.run_forever)