首先针对Thread 我们主要总结一下两部分:
一、如何创建线程,实现方法如下:
(1)其他类继承Thread,同时重写run方法。 具体实例如下:
需要注意的是我们可以把main方法 这边看成是主线程 因为一个进程最少有一个线程 一般在我们不额外开其他线程的时候 就只有main 和这个主线程。
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。(有一种不常用的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束)
如下图: 这里就是所有线程都结束了 进程才结束。
(2)使类实现Runnable接口 同时重写接口里面的run方法。 具体实例如下:
此处声明:t.start()相当于是启动线程 而我们的Runnable 只是一个任务。Runnable 它由哪个线程执行对它自己来说无所谓 我们 放到new Thread(runnable);里他就在2线程运行。
(3)使类继承Thread,同时重写run方法,此处使用匿名内部类的方法。
具体实例如下: 此处和(1)的区别主要在 应该new Thread(); 改为new Thread(){
} ;这就是匿名内部类中 (extends继承类) 的一种用法。
(4)使类实现Runnable接口 同时重写接口里面的run方法,此处使用匿名内部类的方法。
具体实例如下:
此处和(2)的区别在于 (2)处是吧Runnable 放到Thread里 即 new Thread(Runnable);
而此处的相当于在 Thread() 括号里 给他new 一个Runnable 对象 ,同时重写run 方法。这也是匿名内部类中(接口类)的一种方法。(其实不常用 ,确实有点难理解(我认为的))
(5) 最最常用的一类!! 使用lambda表达式
具体实例如下:
专业解释太晦涩难懂 ,通俗的来说就是 我们这里把new Thread(); 在括号里加了一个 -> { }
整体就是 new Thread ( -> { ......} );这样写就省略了我们前面写的需要重写run 方法的步骤,
直接{ }里加我们之前run 方法里的东西就行了。
专业解释如下:lambda表达式,本质上是一个匿名函数,主要用来实现回调函数的效果
二、Thread 的一些重要属性和方法
(1)首先是线程的启动
start方法:本质就是调用系统api ,在系统内核中创建出线程。
run方法:描述该线程要执行的内容(会在我们start之后自动被调用)
他们的本质区别在于是否创建了一个新的线程。
(2)中断一个线程
interrupt 首先我们要知道如果直接使用interrupt可以直接中断线程。
但如果该线程有sleep则有下列情况。
报错但是不停线程。异常确实是出现了 ,sleep也确实是唤醒了,但是上述t1仍然在工作!! 其实原因很简单 ,在Thread内部有一个标志位用来判断线程是否结束, 我们此处interrupt 唤醒线程后 相当于把这个标志位变成 true了 ,但是当sleep抛出异常后,它又会重置标志位,然后线程就又继续走了。 其实这个操作看起来有点矛盾但是 根本目的是为了让了让我们有更高的自由度(如第2个图)。
我们要明白我们既然 interrupt 了就是想尽快结束这个线程,此处的设置相当于在出现这种情况的时候的应急安排或者说最初编写时候的预防御。
(3)线程等待
让一个线程等待另外一个线程执行结束,再继续执行,本质上就是控制线程结束的顺序。
主线程中调用 t1.join() 此时就是让主线程等待 t1 线程结束。