深度解析多线程的创建方式和正确启动多线程

深度解析多线程的创建方式和正确启动多线程

首页枪战射击多线程更新时间:2024-04-30


一、创建多线程

Java 实现多线程的方式准确来说有两种(oracle官方文档说的):

代码演示:

/***用Runnable方式创建线程*/publicclassRunnableStyleimplementsRunnable{@Overridepublicvoidrun(){System.out.println("我是一个Runnable");}publicstaticvoidmain(String[]args){newThread(newRunnableStyle()).start();}}

/***用Thread方式创建线程*每个线程只能操作当前线程类的对象变量,耦合性太强*/publicclassThreadStyleextendsThread{@Overridepublicvoidrun(){System.out.println("我是一个thread");}publicstaticvoidmain(String[]args){newThreadStyle().start();}}

方法1(实现Runnable接口)更好的三个优势:

####(2)节约资源,每次新建任务无需每次都新建线程,例如线程池类使用继承Thread的方式的话,那么每次想新建一个任务,只能新建一个独立的线程,而这样做的损耗会比较大(比如重头开始创建一个线程、执行完毕以后再销毁等。如果线程的实际工作内容,也就是run()函数里只是简单的打印一行文字的话,那么可能线程的实际工作内容还不如损耗来的大)。如果使用Runnable的方式,只需要更换Runnable实例,不需要新建Thread类,就可以实现线程的重复利用,线程池就是基于这个原理,从而大大减小损耗。####(3)可扩展性好,可用实现多继承接口,不能实现多继承类继承Thread类以后,由于Java语言不支持双继承,这样就无法再继承其他的类,限制了可扩展性。###3.两种方法的本质对比方法一和方法二,也就是“实现Runnable接口并传入Thread类”和“继承Thread类然后重写run()”在实现多线程的本质上,并没有区别,都是最终调用了start()方法来新建线程。这两个方法的最主要区别在于run()方法的内容来源:```java...publicclassThreadimplementsRunnable{privateRunnabletarget;...@Overridepublicvoidrun(){if(target!=null){target.run();}}...}

方法一:最终调用Runnable实例的run()方法(target.run());

方法二:直接将Thread类的里整个 run() 方法重写

如果 同时使用Runnable、Thread两种方法,那么只会执行 Thread 中重写的 run()方法,因为将父类中的run方法覆盖了:

...publicclassThreadimplementsRunnable{privateRunnabletarget;...//该run方法直接被重写了,便不再会执行target.run()方法了@Overridepublicvoidrun(){if(target!=null){target.run();}}...}

同时执行两种方式的测试:

/***同时执行两种方式的测试*匿名内部类*/publicclassDoubleStyle{publicstaticvoidmain(String[]args){newThread(()->{System.out.println("我是Runnable");}){@Overridepublicvoidrun(){System.out.println("我是Thread");}}.start();}}

执行结果:

我是Thread的run方法

准确的讲,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式:一是实现Runnable接口的run方法,并把Runnable实例传给Thread类,二是重写Thread的run方法(继承Thread类)

其它创建线程的方式也有很多,但都是在代码的写法上的千变万化,本质上还是都基于 Thread 类和 Runnable 类的重写run()方法。比如以下几种方式:

演示代码:

/***描述:定时器创建线程*/publicclassDemoTimmerTask{publicstaticvoidmain(String[]args){Timertimer=newTimer();timer.scheduleAtFixedRate(newTimerTask(){@Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName());}},1000,1000);}}

其中 TimerTask 又是实现了 Runnable 接口 的类。

所以,本质上,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式:一是实现Runnable接口的run方法,并把Runnable实例传给Thread类,二是重写Thread的run方法(继承Thread类)

代码测试:

publicclassStartAndRunMethod{publicstaticvoidmain(String[]args){Runnablerunnable=()->{System.out.println(Thread.currentThread().getName());};runnable.run();newThread(runnable).start();}}

测试结果:

mainThread-0

可见 run() 只是在主线程中调用了 run 方法,没有启动子线程,这显然不符合我们开启新线程的预期;而 start() 启动了一个子线程,并调用了线程中的run方法。

下面就这两种方法进行解析:

执行start方法是请求 JVM 开辟一个子线程,但线程具体什么时候开始执行,取决于CPU的调度,有可能立即执行,也有可能因为繁忙稍后执行或不执行。

start方法的执行流程:

注意点:

源码:

run()方法重写的两种方式:

文章来源:


微信公众号名称:Java知者

微信公众号id:JavaZhiZhe

欢迎关注,谢谢!


,
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved