
前两种我们在之前的文章中已经讲过了,通过第三、四种我们可以给线程对象命名。
默认情况下,线程对象名字是Thread-N,N是从0开始增加。

start()方法可以开启一个线程,线程创建好后是不会开始执行的,要使用start来开启。
主线程就是main()方法中的线程。
调用start方法后,操作系统层面才会真的创建一个线程。
join()方法可以可以等待一个线程。
join(t)表示等待一个线程t毫秒。
比如在main方法种有两个线程t1、t2,在主线程中有t1.join() ,那么主线程就要阻塞 等待t1线程执行完了才能在执行。如果在t1线程中有t2.join(),那么t1线程就要阻塞 等待t2线程执行完了才能执行任务。
currentThread()方法能获取当前线程对象的引用。
Thread.sleep(1000)能让线程休眠1000毫秒,即在这个时间内停止执行任务。
可以通过getName()方法来获取当前Thread对象的名字
通过getId()获取Thread对象的编号,这是JVM默认为Thread对象生成的编号,属于Java层面,要与PCB中的PID区分,这是属于操作系统层面的。
getState()方法可以获取当前Thread对象的状态,这是Java层面定义的线程状态,要注意和PCB上的区分。
线程有6种状态:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED。

NEW表示创建好了一个Java线程对象,安排好了任务,只是还没有启动,没有调用start方法之前是不会创建PCB的,和PCB没有关系。
RUNNABLE是运行状态或就绪状态,在操作系统层面已经有了对应的PCB。
BLOCKED是阻塞状态的一种,在等待锁🔒
WAITING表示一直没有时间限制的等待,一直等直到被唤醒。
TIMED_WAITING指定了等待时间的阻塞状态,过时就继续执行任务。
TERMINATED是执行结束,PCB已经销毁,Java层面的线程对象还在。
可以查看Thread对象的所有状态:
public class Demo {
/**
* 查看JDK中Thread对象的所有状态
*/
public static void main(String[] args) {
//线程状态定义在一个枚举中
for(Thread.State state: Thread.State.values()){
System.out.println(state);
}
}
}

wait()和notify()是object类中的方法,要搭配使用。
join()、sleep()是Thread类中的方法。
getPriority()能获取线程的优先级,理论上优先级高的更容易被调度到。
isDaemon()方法能判断线程是否是后台线程。非后台线程即前台线程不会随主线程的结束而结束,而后代线程会随主线程的结束而结束。
创建线程默认是前台的,setDaemon(true)可以将线程设置为后台线程。
JVM会在所有非后台线程都结束了才会结束运行。
public class Demo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(true){
System.out.println(Thread.currentThread() + "hello");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
//thread.start();
System.out.println("线程是否存活:" + thread.isAlive());
System.out.println("线程是否为后台线程 "+ thread.isDaemon());
//将线程设置为后台线程
thread.setDaemon(true);
thread.start();
System.out.println("线程是否存活:" + thread.isAlive());
System.out.println("线程是否为后台线程 "+ thread.isDaemon());
int i = 0;
while(i < 2){
i++;
Thread.sleep(1000);
System.out.println("main()主线程没有结束……");
}
Thread.sleep(1000);
System.out.println("结束main()主线程");
}
}
可以看到设置成后台线程之后,main方法结束后子线程也随之结束了。
前台线程可以阻止进程的退出,后台线程不能阻止进程的退出。
isAlive()方法能判断线程是否存活,如果线程还没开启或者任务执行完成,则线程死了。
描述的是PCB的状态,能判断出run()方法是否执行完成。
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for(int i = 0; i < 5; i++){
System.out.println("hello thread...");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("线程任务完成。");
});
System.out.println("启动之前查看线程是否存活:" + thread.isAlive());
thread.start();
System.out.println("启动之后查看线程是否存活:" + thread.isAlive());
thread.join();
Thread.sleep(1000);
System.out.println("线程结束之后查看线程是否存活:" + thread.isAlive());
}
isInterrupted()判断线程的中断状态。
两种中断方式:
1、自定义标识位,通过修改标识位来通知线程中断
public class Demo_207 {
private static boolean isQuit = false;
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(()->{
while(!isQuit){
System.out.println(Thread.currentThread().getName() + "hello");
}
System.out.println("线程结束咯");
});
System.out.println("线程是否存活:" + thread.isAlive());
System.out.println("线程状态:" + thread.getState());
System.out.println("线程是否中断:" + thread.isInterrupted());
thread.start();
isQuit = true;
//等待线程销毁
Thread.sleep(100);
System.out.println("线程是否存活:" + thread.isAlive());
System.out.println("线程状态:" + thread.getState());
System.out.println("线程是否中断:" + thread.isInterrupted());
}
}注意在lambda表达式中如果使用局部变量会触发“变量捕获”,所以我们需要把变量定义为全局的。

2、通过interrupt()来通知线程中断
public class Demo_208 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello Thread~");
try{
//休眠时间1s,休眠时间远大于执行任务的时间,所以线程大部分时间都在sleep
//sleep时被中断会触发异常,要处理中断逻辑
Thread.sleep(1000);
}catch(InterruptedException e){
//处理中断逻辑
e.printStackTrace();
System.out.println("休眠被中断啦!");
break;
}
}
System.out.println("线程退出……");
});
System.out.println("线程是否存活:" + thread.isAlive());
// 启动线程
thread.start();
// 主线程休眠一会
Thread.sleep(1000);
System.out.println("线程是否存活:" + thread.isAlive());
// 中断线程,发出中断信号
thread.interrupt();
// 等待线程销毁
Thread.sleep(100);
// 查看是否存活
System.out.println("线程是否存活:" + thread.isAlive());
}
}
当线程处于休眠状态、等待状态时被中断,就会出现这个异常,我们需要在catch语句中处理中断逻辑。
如果线程是在正常运行状态下被中断,不会出现这个异常,直接中断线程。
一个简单代码示例展示使用以上方法:
public class Demo{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for(int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName() + " 还活着哟");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 我将死去");
},"kiku线程");
System.out.println(thread.getName() + " ID:" + thread.getId());
System.out.println(thread.getName() + " 名称:" + thread.getName());
System.out.println(thread.getName() + " 状态:" + thread.getState());
System.out.println(thread.getName() + " 优先级:" + thread.getPriority());
System.out.println(thread.getName() + " 后台线程:" + thread.isDaemon());
System.out.println(thread.getName() + " 是否活着:" + thread.isAlive());
System.out.println(thread.getName() + " 是否被中断:" + thread.isInterrupted());
//启动线程
thread.start();
System.out.println(thread.getName() + " ID:" + thread.getId());
System.out.println(thread.getName() + " 名称:" + thread.getName());
System.out.println(thread.getName() + " 状态:" + thread.getState());
System.out.println(thread.getName() + " 优先级:" + thread.getPriority());
System.out.println(thread.getName() + " 后台线程:" + thread.isDaemon());
System.out.println(thread.getName() + " 是否活着:" + thread.isAlive());
System.out.println(thread.getName() + " 是否被中断:" + thread.isInterrupted());
//主线程等待thread线程执行任务结束
thread.join();
System.out.println(thread.getName() + " ID:" + thread.getId());
System.out.println(thread.getName() + " 名称:" + thread.getName());
System.out.println(thread.getName() + " 状态:" + thread.getState());
System.out.println(thread.getName() + " 优先级:" + thread.getPriority());
System.out.println(thread.getName() + " 后台线程:" + thread.isDaemon());
System.out.println(thread.getName() + " 是否活着:" + thread.isAlive());
System.out.println(thread.getName() + " 是否被中断:" + thread.isInterrupted());
}
}