首先在深入了解线程创建之前分析下面代码:
运行结果每秒钟(每次唤醒sleep)先执行main还是先执行thread是不一定的
进程创建第一线程开销最大,剩下的线程开销都比较小,但不是0
线程创建方式
1.继承Thread重写run
eg:在run里写代码
2.实现Runnable接口,重写run
eg:Runnable--可执行的,通过这个接口可以抽象表示一段其他实体执行代码
一段可执行代码:
Runnable runnable =new MyThread3() ;
Thread t=new Thread(runnable );
t.start();
这里需要搭配Thread类,才能真正在系统中创建出线程,这里将线程和要执行的任务进行了解耦合
3.匿名内部类--继承Thread,重写run
使用匿名内部类(在一个类里面定义的类,最大的用途,匿名内部类-不能重复使用)
写{}是要定义一个类,与此同时这个新的类继承自Thread,也创建了子类实例(t
此处{}中可以定义子类的属性和方法,此处最主要的目的就是重写run方法
调用以下代码线程才能出来
t.start();
4.匿名内部类,实现Runnable,重写run
Thread t=new Thread(new Runnable() {
@Override
public void run() {
}
}};//Thread构造方法填写了Runnable的匿名内部类
Thread构造方法的参数填写了Runnable的匿名内部类的实例
匿名内部类总结:方法不能脱离类单独存在,为了设置回调函数,套上类,引入lambda(匿名函数)
5.推荐!!-使用lambda表达式
lambda主流语言都有,其中JS,Go叫做匿名函数
lambda表达式如下:
public static void main(String[] args) {
Thread t=new Thread(()-> {
});
lambda代码在创建方式最简洁如下:
Thread t=new Thread(() -> {//此处()为形参列表,这里能带参数
//线程的入口不需要参数,使用lambda代替Comparator,可以带上两个参数()前面应该有一个函数名
//此处作为匿名函数没有名字
while (true) {
System.out.println("hello thread");
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
这个写法相当于实现Runnable重写run,lambda代替了Runnable的位置
lambda表达式本质:函数式接口=>匿名内部类(可以访问到外面定义局部变量)
变量捕获语法规则(本质是传参):这个捕获的变量是final或者“事实final"
编译器编译的时候,Thread构造方法挨个往里匹配,其中匹配到Runnable这个版本刚好能对上
这里有个run方法,无参数,正好和lambda能匹配上
总结:上述5种写法都是等价的,可以互换~~~
方法 | 说明 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象并命名 |
Thread(Runnable target,String name) | 使用Runnable对象创建线程对象并命名 |
创建线程默认按照Thread -0 1 2 3 4...为了方便调试
Thread其他的重要属性和方法
属性 | 获取方法 |
ID | getId()--jvm自动分配的身份标识会保证唯一性 |
名称 | getName() |
状态 | getState()--进程有状态(就绪状态,阻塞状态) |
优先级 | getPriority()--进程优先级在java效果不明显对内核调度器调度过程有影响(系统随机调度) |
是否后台进程/线程 | isDaemon()--daemon-守护线程 |
是否存活 | isAlive()-内核中的线程(PCB)是否还存在 |
是否被中断 | isInterrupted() |
注:
1.前台线程的运行会阻止进程结束;后台线程的运行不会阻止线程结束;
2.java 代码中定义的线程实例虽然表示一个线程,但是这个实例本身的生命周期和内核中 PCB 的生命周期是不完全一样的;
eg:
Thread t = new Thread(()-> {//此时t对象有但是内核PCB还没有 isAlive就是fasle
...
})
t.start()//真正在内核中创建出PCB,此时isAlive就是true
当线程run执行完此时内核中的线程结束(内核pcb就释放了)但此时t变量可能还存在于是isAlive也是fasle