线程的命名
可以给线程起名(中文名也是可以的),例如对三个线程起不同名字再去jconsole上观察
java
public class Demo06 {
public static void main(String[] args) {
Thread t1=new Thread(()->{
while(true){
System.out.println("hello t1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread t2=new Thread(()->{
while(true){
System.out.println("hello t2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread t3=new Thread(()->{
while(true){
System.out.println("hello t3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});

当不给线程起名的时候,线程会自动命名为Thread-0,Thread-1....

通过名字描述线程是干啥的,方便调试
主线程

main方法执行完毕,主线程就已经结束了
以前我们对于main的认识是当main方法执行完之后,程序就已经结束了(进程);但实际上,以前的
认知是针对于单线程程序
Thread 类及常见方法
Thread 类是JVM用来管理线程的一个类,换句话说,每个线程都有一个唯一的Thread 对象与之关 联。
Thread 的常见构造方法
|-----------------------------------------------|----------------------------|
| 方法 | 声明 |
| Thread() | 创建线程对象 |
| Thread(Runnable target) | 使用Runnable对象创建线程对象 |
| Thread(String name) | 创建线程对象,并且命名 |
| Thread(Runnable target,String name) | 使用Runnable对象创建线程对象,并命名 |
| 【了解】Thread(ThreadGroup group,Runnable target) | 线程可以被用来分组管理,分好的组即为线程组,了解即可 |
Thread 的几个常见属性
|--------|-----------------|
| 属性 | 获取方法 |
| ID | getId() |
| 名称 | getName() |
| 状态 | getState() |
| 优先级 | getPriority() |
| 是否后台线程 | isDaemon() |
| 是否存活 | isAlive() |
| 是否被中断 | isInterrupted() |
ID 是线程的D唯一标识,不同线程不会重复,标识线程身份的效果,类似于PID
Daemon
关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
例如,当main线程虽然结束了,但是t1,t2.t3还在,所以进程仍然存在,t1,t2,t3这样的线程就称为
"前台线程"

黑框部分是JVM自带的线程,这些线程不影响进程的结束,如果进程要结束了,即使这些线程继续
运行,也会随之结束,这些就是后台线程
我们创建的代码包括main线程都默认是前台线程,但可以通过setDaemon方法来进行修改
java
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.setDaemon(true);
t.start();
for (int i = 0; i < 2; i++) {
System.out.println("hello main");
Thread.sleep(1000);
}
System.out.println("main结束");
}
把t设为后台线程,无力阻止main线程的结束,这样的设置得在start之前运行
isAlive()
创建Thread对象和系统中的线程关系是一一对应的,但是Thread对象的生命周期和系统中的线程的生命周期是不同的(可能存在,Thread对象存活,但是系统中的线程已经销毁的情况)
java
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
System.out.println(t.isAlive());
t.start();
while (true){
System.out.println(t.isAlive());
Thread.sleep(1000);
}

当for循环结束之后,线程的入口方法的逻辑结束了,系统中对应的线程就随之销毁了
但是对应的t对象会仍然存在
启动线程-start()
java标注库/JVM提供的方法,本质上是调用操作系统的API
每个Thread对象,都是只能start一次的
每次创建一个新的线程,都得创建一个新的Thread对象(不能重复利用)
start和run的区别
run是线程的入口方法,不需要手动调用
start是调用系统api
二者本质上没有很大的关系
中断线程
1.通过共享的标记来终止
java
private static boolean isFinished=false;
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (!isFinished){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
Thread.sleep(3000);
isFinished=true;
}
通过定应全程变量来控制线程进度
但当isFinished变为局部变量时,此时无法对其进行修改

通过观察报错原因我们可以知道,这个isFinished应该为常量

这与我们前面的isFinished修改相互矛盾,这其实是因为lambda里面希望使用外面的函数,触发了
变量捕获的语法

lambda是回调函数,执行时机是很久之后(操作系统真正创建线程之后,才会执行),可能会出
现后续线程创建好了,但是当前main这里的方法都执行完了,对应的isFinished就销毁了
Java为解决上述的问题把捕获的变量拷贝一份在lambda里面,外面的变量是否销毁都不会影响
lambda里面的执行
这里的拷贝意味着这样的变量就不再适合修改(修改的本质是修改一方,另一方不会随之变化)
让isFinished变为静态变量时,isFinished在类加载时就会存在,而不是通过new时才会存在
而对于引用类型,引用本身是不能修改(不能修改这个引用指向的其他对象),但是引用指向的对象
本体是可以修改的

把上述的代码改成员变量此时不再是"变量捕获"语法,而是切换成"内部类访问外部类的成员"语法
lambda本质上是函数式接口,相当于一个内部类,isFinished就是外部类的成员,内部类就是能够
访问到外部类的成员,成员变量生命周期也是让GC来管理的,在lambda里面不担心变量生命周期
失效的问题,也就不必拷贝,也就不必限制final之类的
调用 interrupt() 方法
Java的Thread对象中提供了现成的变量,直接进行判定,不需要自己创建了
lambda这里的定义是在new Thread之前,也是在Thread t声明之前,所以Thread创建的对象也无
法在lambda表达式中使用

Thread提供了访问当前对象的静态方法currentThread(),获取到的就是那个线程的Thread引用
java
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t结束了");
});
t.start();
Thread.sleep(3000);
System.out.println("main尝试终止t线程");
t.interrupt();
System.out.println(Thread.currentThread().getName());
}
判定Thread里的boolean变量的值,判定线程是否终止了

主动去进行终止,修改这个boolean变量的值,除了设置boolean变量(标志位)之外,还能够唤醒
sleep这样的阻塞方法

这个线程掀桌了,可以通过修改抛出异常的部分来控制终止
加上break是立即终止


啥都不写就是不终止


catch中执行一些逻辑在break,就是稍后终止

