博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java线程启动原理分析
阅读量:4622 次
发布时间:2019-06-09

本文共 4871 字,大约阅读时间需要 16 分钟。

一、前言

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

其实我想对于任何一门技术的学习都是这样。
形而上下者为之器,形而上者为之道。一直很喜欢自己大一的高数老师,老师是老教授了,他讲数学,会引申到建筑学,计算机科学,以及哲学再到生活中的常识。也能从其他学科、日常生活中,提取出数学的概念。我想,这就是形而上者了。
不胜望之
不多言,这里我们来深入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
铛铛铛档

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,它将被传递给调用堆栈。                 */            }        }    }

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

虽然为同步方法,但不能避免多次调用问题,用threadStatus来记录线程状态,如果线程被多次start会抛出异常;threadStatus的状态由JVM控制。
使用Runnable时,主线程无法捕获子线程中的异常状态。线程的异常,应在线程内部解决。

2、native start0方法

private native void start0();

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(); } }

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

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

四、总结

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

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

五、参考

https://www.jianshu.com/p/8c16aeea7e1a

转载于:https://www.cnblogs.com/xuyuanpeng/p/11050394.html

你可能感兴趣的文章
LeetCode -- Increasing Triplet Subsequence
查看>>
hdu 2114 Calculate S(n) 数论(简单题)
查看>>
hdu 5984
查看>>
解决:Incorrect line ending: found carriage return (\r) without corresponding newline (\n)
查看>>
深入学习微框架:Spring Boot
查看>>
Coprimes - SGU 102(求互质数,水)
查看>>
CSS布局(二) 盒子模型属性
查看>>
jQuery 获取select选中的option
查看>>
更新被拒绝,因为您当前分支的最新提交落后于其对应的远程分支
查看>>
LeetCode 112. Path Sum (二叉树路径之和)
查看>>
mysql数据恢复
查看>>
java list
查看>>
算法练习2---斐波那契数列java版
查看>>
用VISIO2013绘制E-R图
查看>>
每日站立会议03
查看>>
软件工程第一次作业
查看>>
初步了解HTML
查看>>
九度OJ 1165:字符串匹配 (模式匹配)
查看>>
Swift Storyboard找不到类文件
查看>>
Hibernate-延迟加载和立即加载
查看>>