欢迎各位!!!推荐PC端观看
文章重点:学会五种线程的创造方式
目录
1.开启线程的五种方式
2.线程的构造方法
3.线程的属性及获取方法
1.开启线程的五种方式
创造线程的基本两步:(1)使用run方法记录线程要做的任务(2)使用线程的引用 调用start开启线程
1.1.继承Tread,重写run
class myThread extends Thread {@Overridepublic void run() {System.out.println("继承Thread,重写run");}
}
public class Func1 {public static void main(String[] args) {Thread t = new myThread();t.start();}
}
(1)Thread线程自己在run中记录了线程要做的任务
(2)main函数中通过t引用开启线程
1.2.实现Runnable,重写run
class myRunnable implements Runnable {@Overridepublic void run() {System.out.println("实现Runnable,重写run");}
}
public class Func2 {public static void main(String[] args) {myRunnable t = new myRunnable();Thread t2 = new Thread(t);t2.start();}
}
(1)实现Runnable接口,此时记录任务的是一个单独的类
(2)t开启线程之和,线程需要到前面的类中寻找线程任务
(3)相比第一种来说,安全性更高
1.3.继承Thread,使用匿名内部类
第一种写法的变形
public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {System.out.println("继承Thread,使用匿名内部类");}};t.start();}
1.4.实现Runnable,使用匿名内部类
第二种写法的改进写法
public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("实现Runnable,使用匿名内部类");}});t.start();}
1.5.使用lambda表达式
public static void main(String[] args) {Thread t= new Thread(()->{System.out.println("使用lambda表达式执行线程");});t.start();}
线程创造方式的推荐:第五种>第四种>三>二>一
1.6.查看多线程运行
6.1.直接通过代码观察
代码:
class myThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("t线程ttttt");}}
}
public class demo1 {public static void main(String[] args) {Thread t = new myThread();t.start();while (true) {System.out.println("主线程9999");}}
}
运行结果:
6.2.通过jconsole.exe观察
(1)找到该文件位置
(2)运行代码后选择
(3)可以看到,此时线程正在运行。Thread-0就是我们自己创造的t线程,main线程是主线程,运行程序就会有
1.7.线程小结
(1)按照上面五种方式创建完线程之后,需要通过线程的引用开启线程。例如 t 就是一个线程引用,t.start()就是开启了该线程,后面会介绍该方法。
(2)前面的四种线程创造方法,都需要重写run,而使用lambda表达式不需要。其本质都是为了记录该线程的任务。等待t.start()后就会执行该任务
2.线程的构造方法
下面是一个Thread线程构造函数表
2.1.Thread()
这种构造方法,就是我们上面使用的第一种创造线程的方法,但是要发生向上转型,一般不会直接new;也可以是第五种
2.2.Thread(Runnable target)
这种也就是上述的第二种线程创造方式和第四种
(1)上述第二种
(2)上述第四种
2.3.Thread(String name)
这种是给线程起名字
(1)没有给线程起名字时
当我们自己创建的线程没有起名字时,第一个线程默认为:Thread-0,第二个为:Thread-1,以此类推
(2)起了名字后
起名字的写法一般是后面几种创造线程的方式才可以
3.线程的属性及获取方法
下面是Thread常见的几个属性和获取方法
这里线程的一些属性,有些neri
3.1.ID
这里的id和pcb中的id不是同一个东西,但是都是唯一标识符。而且,在java代码中是无法获取到该属性,所以也就不过多叙述了。
3.2.名称
这里的名称也就是可以通过上面介绍的构造方法设置的。
通过getName()方法就可以找到该线程的名字
3.3.状态
线程的状态有五种:新建状态(NEW)、就绪状态(RUNNABLE)、运行状态(RUNNING)、阻塞状态(BLOCKED)、死亡状态(DEAD)
至于每种状态代表什么、是怎么来的、状态之间是怎么切换,我们这里不做介绍,后面会有专门一部分来叙述。
获取当前线程的状态:
3.4.优先级
实际上修改了优先级,但是现象也不明显。所以这里的修改优先级仅供参考,也就不做其他详细的介绍
3.5.是否后台线程(*)
(1)介绍后台线程和前台线程
前台:如main所在的主线程,前台线程不运行结束的话,java进程一定不会结束。而且前台线程有很多个,只有都结束了,Java程序才会结束
后台:这样的线程 对进程不起决定作用(也称为daemon,后台线程)
我们创造的线程和主线程都默认是前台线程。
(2)举例子说明前后台程序
举办酒席:主持人、官方人员和主人这些,我们记为前台程序;而像我们这些干饭人则称为后台线程。酒席是否结束我们就记为Java程序是否结束
(1)我们这些干饭人,吃完饭就直接走,不会影响酒席的结束与否
(2)当主持人这些前台程序宣布酒席到此结束的时候,酒席就会直接结束。即使干饭人的我没有吃完,也不能继续干饭了(后台程序也结束了)
(3)通过setDaemon方法可以把线程设置为后台线程
方法内默认加上true
如果不把t线程设置为后台线程,该程序是不会结束的
(4)注意事项
线程的各种属性设置都要在start前面,否则报错
3.6是否存活(*)
(1)是否存活:指的是系统中的线程(PCB)是否存在。而Thread对象的生命周期,和PCB的生命周期是不一定完全一样的。
(2)区别
他们的诞生的时间:
当线程创建出来的时候,pcb才会出现并且添加到链表上
他们的结束的时间:
t线程一下子就执行完了,因此pcb的一下子就结束了;而t指向的Thread对象,因为sleep还没执行完,因此还没被GC回收
他们的第二种结束时间:
这种写法,t线程里面会休眠一段时间才会结束,而Thread对象一下子就被GC回收了。
结论:说明他们之间没有什么关系,无法真正的判断线程是否结束了,所以可以通过isAlive()方法判断当前的线程是否还存货。
(3)判断线程是否存活
因为上面的情况,Thread对象和线程的生命周期不完全一样,所以不容易直接判断,就需要借助一些方法来获取当前线程的属性-是否存活
1)线程未结束
2)线程已结束
3.7是否被中断
这里只简单的查看一个线程是否被中断,至于如何中断一个线程,在后面介绍线程的核心操作部分介绍。
(1)查看一个死循环线程
(2)有限线程
这种判断,即使一个线程自己结束了,也显示false
上面的重点是:五种线程的创建方式、给线程起名字、是否后台线程、是否存活这些等等;而线程的状态、是否被中断,在接下来的文章中重点介绍。