0%

JAVA Thread Start与Run调用

  • start() && run() 源码
  • 区别
  • Demo及Demo遇到的问题 (Method Reference)

Thread

Source Code

Thread start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();

/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);

boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}

Thread run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}

Diff

start() 方法是真正的启动方法,是并行调用的

run()是Thread中的一个方法,是串行调用的

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class ThreadTest {
public static void main(String[] args) {
Thread noPrintRunThread = new Thread(MyRunnable::new);
noPrintRunThread.run();
noPrintRunThread.start();
System.out.println("No Print End");

Thread runThread = new Thread(new MyRunnable());
runThread.run();
System.out.println("run-1");
runThread.run();
System.out.println("run-2");


Thread startThread1 = new Thread(new MyRunnable());
startThread1.start();
System.out.println("start-1");

Thread startThread2 = new Thread(new MyRunnable());
startThread2.start();
System.out.println("start-2");
startThread2.start();

System.out.println("start-2 Again");
//if (threadStatus != 0)
// throw new IllegalThreadStateException();
}


static class MyRunnable implements Runnable {

@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
System.out.println("i:" + i);
Thread.sleep(300);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

/**
* No Print End
* i:0
* i:1
* i:2
* run-1
* i:0
* i:1
* i:2
* run-2
* start-1
* i:0
* start-2
* i:0
* Exception in thread "main" java.lang.IllegalThreadStateException
* at java.lang.Thread.start(Thread.java:708)
* at ThreadTest.main(ThreadTest.java:20)
* i:1
* i:1
* i:2
* i:2
*
* Process finished with exit code 1
*/

Demo Encountered Problem

If Thread Start Twice

  • 根据Thread start()源码可知,状态异常会抛出IllegalThreadStateException()异常

    1
    2
    3
    4
    5
    6
    7
    8
    Thread startThread2 = new Thread(new MyRunnable());
    startThread2.start();
    System.out.println("start-2");
    startThread2.start();

    System.out.println("start-2 Again");
    //if (threadStatus != 0)
    // throw new IllegalThreadStateException();

Method Reference Problem

  • 使用方法引用启动的线程不论是run()还是start()方法都不会真正调用

    1
    2
    3
    4
    Thread noPrintRunThread = new Thread(MyRunnable::new);
    noPrintRunThread.run();
    noPrintRunThread.start();
    System.out.println("No Print End");
  • ChatGPT回答

    1
    2
    3
    4
    5
    Regarding your question, when you use a method reference like MyRunnable::new, you're actually referencing a constructor method of the MyRunnable class. When you call the constructor with arguments like new MyRunnable("myRunnable start()"), you're invoking a specific constructor method that takes a string argument.

    In the case of new Thread(MyRunnable::new).start(), the Thread constructor that takes a Runnable argument is being invoked. The MyRunnable::new method reference is a reference to the constructor method that takes no arguments. Therefore, when the Thread object is created and started, the run() method of the MyRunnable object that was created with no arguments is executed.

    To make the code work as you intended, you need to provide a constructor method reference that takes a string argument, like new MyRunnable("MyRunnable with argument")::new. This will create a reference to the constructor method that takes a string argument, and when the Thread object is created and started, the run() method of the MyRunnable object that was created with the string argument is executed.
  • 求证

    • new 与 Object::new

      通过 java - Runnable::new vs new Runnable() - Stack Overflow ,可知Object::new方法是创建一个实例,并不会调用内部的run方法。即如果内部有两个Runnable,之后执行最上层的那个。

      通过构造器引用和直接用new创建对象区别 - lonecloud - 博客园 (cnblogs.com) 字节码查看,方法引用并没有调用init()方法,因此实际上没有真正产生对象

      推断:类似于Spring三级缓存,方法引用实际上只是一个lambda表达式,还没到真正创建对象的状态,没有传入其他参数,不需要进入set属性方法,因此使用 Myrunnable::new 方法并不会生成内部属性,因而没有执行run()方法。

      若理解错误请帮忙指出,谢谢

    • 为什么 MyRunnable::new不生效

      由于只是创建出构造函数的实例,没有真正生成对象,导致内部产生两个Runnable,只会执行最外层方法,无法调用内部run()方法,因此不生效

  • 结论

    • 对于线程创建,不能使用方法引用,只能通过其余方法启动

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      @Test
      public void threadTest() throws InterruptedException {
      // method reference,not working
      CountDownLatch latch = new CountDownLatch(4);
      new Thread(MyRunnable::new,"method reference").start();
      //worked
      new Thread(new MyRunnable("Another Method Reference", latch)::run).start();
      //worked
      MyRunnable myRunnable = new MyRunnable("myRunnable start()", latch);
      new Thread(myRunnable).start();
      //worked
      new Thread(() -> new MyRunnable("MyRunnable.run() start()", latch).run()).start();
      //worked
      new Thread(new MyRunnable("MyRunnable.start()", latch)).start();

      latch.await();
      System.out.println("All Thread Done.");
      }

Source