Java多线程带你用不一样的思维看创建线程的两种方式
Posted 写Bug的渣渣高
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程带你用不一样的思维看创建线程的两种方式相关的知识,希望对你有一定的参考价值。
文章目录
创建线程的两种方式
通过实现 Runnable 接口
public class CreateThread
// 继承 Thread 类来
static class MyThread extends Thread
@Override
public void run()
System.out.println("Hello MyThread");
// 实现 Runnable 接口:这个方式更灵活,因为实现接口后,可以继承其他类
static class MyRun implements Runnable
@Override
public void run()
System.out.println("Hello MyRun");
public static void main(String[] args)
new MyThread().start();
new Thread(new MyRun()).start();
new Thread(()->
System.out.println("hello lambda!");
).start();
上面是主流的创建线程的两种方法,那么我们看一下这两种方法有什么区别吧
Runnable:可以看到使用 Runnable 来创建线程,使用 Runnable 接口引向一个匿名内部类,该内部类重写了 Runnable 接口的run方法,再次之后,仍需要创建一个新的线程,然后传入 runnable ;
Thread : 直接继承 Thread 然后重写 run 方法
从面对对象的角度来思考:
两种方法都是为了构造一个 Thread 类,大家可以看到实现了 runnable 接口后,仍然是创建了一个新的线程,把接口作为 Thread 的构造方法参数传入
public Thread(Runnable target)
init(null, target, "Thread-" + nextThreadNum(), 0);
start 和 run 方法解析
在初次使用的时候,大家很容易看见,我们重写的是 run 方法,那么为什么调用的时候,调用的却是 start 方法
start启动新线程:通知JVM,有空闲就创建新线程,何时创建由线程调度器控制(并非调用start方法就会创建,即两个调用start的方法顺序不代表线程的创建顺序)
调用完start后,在主线程中启动
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 */
为什么不能调用 run 方法 调用了会发生什么事情
public static void main(String[] args)
Runnable runnable = ()->
System.out.println(Thread.currentThread().getName());
;
runnable.run();
new Thread(runnable).start();
main:因为在调用的时候,我们使用的是接口.方法,实际上 runnable 接口指向一个匿名内部类,这个类重写了 run 方法,我们在调用的时候,调用的是普通方法 run ,并且是在主函数里面调用的 主线程就是 main
Thread-0 :
重复调用 start 方法会发生什么事情
Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at StartTwice.main(StartTwice.java:5)
为什么不能重复调用
原因:一旦开始线程完毕,会进入终止状态,无法回退
if (threadStatus != 0)
throw new IllegalThreadStateException();
threadStatus:
Java 线程状态,已初始化以指示线程“尚未启动”
彩蛋:同时用两种方法来实现同一个线程,会遇到什么
大家可能没有考虑过,如果new Thread 类,并且传入一个 runnable 重写 runnable 接口的 run 方法的同时,重写Thread 类的 run 方法会发生什么事情
public static void main(String[] args)
new Thread(new Runnable()
//匿名内部类
@Override
public void run()
System.out.println("Runnable");
)
//重写
@Override
public void run()
System.out.println("Thread");
.start();
从面向对象的思想去考虑:
刚才使用的匿名内部类,然后重写了Thread,
两种,一种是重写run方法,一种是给run传入target
我们看看源码,才能知道为什么调用的是 Thread 类的 run
如果该线程是使用单独的 unnable 运行对象构造的,则调用该 Runnable 对象的run 方法;否则,此方法不执行任何操作并返回。 Thread 的子类应覆盖此方法。
private Runnable target;
@Override
public void run()
if (target != null)
target.run();
解释一下 targer 是我们使用 runnable 方法来构建Thread 类时传入的参数。
这个三行代码是什么,大家思考一下,这个是 Thread 类的 run 方法,我们平时使用的新建 Thread 创建线程,就会重写这个方法,即这个三行代码是被重写的,不会调用。但是如果仅仅只是 runnable 新建线程,我们只是重写了 Runnable 接口的 run 方法,启动线程 Thread 调用的就是未被重写的 这三行Thread 类的run方法中的语句。但两者都有时,Thread 的 run 方法就会被前者覆盖,上方的 run 方法中三行代码永远不会执行
小知识:调用start方法,线程就会立刻启动吗?
- 调用了 start 方法,线程就立刻启动了吗???
在调用 start 方法后,其实先通知JVM,让其有空闲就创建新线程,但是何时真正创建由线程调度器决定。即,在某些情况下,可能会出现先 start 的线程后执行
以上是关于Java多线程带你用不一样的思维看创建线程的两种方式的主要内容,如果未能解决你的问题,请参考以下文章