java看山不是山_java线程启动原理分析

一、前言

不知道哪位古人说:人生三大境界。第一境界是:看山是山看水是水;第二境界是看山不是山看水不是水;第三境界:看山还是山看水还是水。

其实我想对于任何一门技术的学习都是这样。

形而上下者为之器,形而上者为之道。一直很喜欢自己大一的高数老师,老师是老教授了,他讲数学,会引申到建筑学,计算机科学,以及哲学再到生活中的常识。也能从其他学科、日常生活中,提取出数学的概念。我想,这就是形而上者了。

不胜望之

不多言,这里我们来深入java底层,看下java表皮之下的筋肉以及内脏。

二、从一段代码展开

package thread;

/**

* @author xuyuanpeng

* @version 1.0

* @date 2019-05-17 17:04

*/

public class ThreadMain {

public static void main(String[] args) {

Thread thread=new Thread(() -> {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

});

Thread t2=new Thread(() -> {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

});

log("线程1开始");

thread.start();

log("线程1结束");

log("线程2开始");

t2.run();

log("线程2结束");

}

public static void log(String msg){

System.err.print(System.currentTimeMillis());

System.out.println(">>>"+msg);

}

public static void log(){

log("");

}

}

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

这里可以思考下输出的结果:

1

2

3

铛铛铛档

Connected to the target VM, address: ‘127.0.0.1:51304’, transport: ‘socket’

1558085396255>>>线程1开始

1558085396255>>>线程1结束

1558085396255>>>线程2开始

1558085397255>>>线程2结束

Disconnected from the target VM, address: ‘127.0.0.1:51304’, transport: ‘socket’

细心的同学肯定已经发现了

线程1是start的方式启动,而线程2是run方法启动

差异在哪?

线程1执行start,并没有阻塞线程

而线程2的run方法,阻塞了线程。何改咯?┓( ´∀` )┏

为什么是这样的呢?start与run的区别究竟在哪呢?让我们深入她,张爱玲说,了解一个女人最好的通道就是XX,所以让我们深入她,再了解她。

三、JDK源码分析

1、start方法

public synchronized void start() {

/**

/**

* Causes this thread to begin execution; the Java Virtual Machine

* calls the run method of this thread.

*

* 1、start方法将导致当前线程开始执行。由JVM调用当前线程的run方法。

*

* 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).

*

* 2、结果是 调用start方法的当前线程 和 执行run方法的另一个线程 同时运行。

*

* It is never legal to start a thread more than once.

* In particular, a thread may not be restarted once it has completed

* execution.

*

* 3、多次启动线程永远不合法。 特别是,线程一旦完成执行就不会重新启动。

*

* @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.

*

* 4、对于由VM创建/设置的main方法线程或“system”组线程,不会调用此方法。

* 未来添加到此方法的任何新功能可能也必须添加到VM中。

*

* A zero status value corresponds to state "NEW".

* 5、status=0 代表是 status 是 "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.

*

* 6、通知组该线程即将启动,以便将其添加到线程组的列表中,

* 并且减少线程组的未启动线程数递减。

*

* */

group.add(this);

boolean started = false;

try {

//7、调用native方法,底层开启异步线程,并调用run方法。

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

* 8、忽略异常。 如果start0抛出一个Throwable,它将被传递给调用堆栈。

*/

}

}

}

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

start方法用synchronized修饰,为同步方法;

虽然为同步方法,但不能避免多次调用问题,用threadStatus来记录线程状态,如果线程被多次start会抛出异常;threadStatus的状态由JVM控制。

使用Runnable时,主线程无法捕获子线程中的异常状态。线程的异常,应在线程内部解决。

2、native start0方法

private native void start0();

1

native 是声明本地方法,在此处是JVM中的方法。

3、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.

*

* @see #start()

* @see #stop()

* @see #Thread(ThreadGroup, Runnable, String)

*/

@Override

public void run() {

if (target != null) {

target.run();

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

run方法就很简单了,就是回调了Runable的run()接口

导致Thread写的@Overwrite void run() 方法直接是在主线程执行,导致阻塞了主线程。

四、总结

到此我们就知道了,start会使重写的run方法被虚拟机调用,是在子线程中执行的run方法

而直接调用线程的run方法,他是内部回调了run接口,导致直接执行了Runable.run的重写内容。相当于直接在主线程中执行。

---------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值