1、线程的类和方法
Thread类是JVM用来管理线程的一个类,换句话说,每个线程都有唯一一个的Thread对象与之关联。
1.1、Thread的常见方法
方法 | 说明 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象并命名 |
Thread(Runnable target,String name) | 使用Runnable对象创建线程对象,并命名 |
【不常用】Thread (ThreadGroup group,Runnable target) | 线程可以用来分组管理,分好的组即为线程组 |
Thread t1=new Thread();
Thread t2=new Thread(new MyRunnable());
Thread t3=new Thread("线程的名字");
Thread t4=new Thread(new MyRunnable(),"线程的名字");
1.2、Thread的几个常见属性
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
Thread类是JAVA中的类,我们通过java代码创建Thread对象是java中的对象,调用start方法后,通过JVM去申请操作系统中的线程PCB,线程的对象是与PCB是一一对应的关系,但是他们的生命周期是不同的。
2、示例
2.1、后台线程的演示
public class Exe_02 {
public static void main(String[] args) {
//创建一个线程
Thread thread=new Thread(()->{
while(true){
System.out.println("你干嘛,哎呦");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//设置成后台线程
thread.setDaemon(true);
//启动线程
thread.start();
//查看线程是否存活
System.out.println("是否存活"+thread.isAlive());
System.out.println("main方法执行完成");
}
}
设置为后台线程时,mian方法执行完成之后,,整个线程就退出了
1、线程在创建的时候,默认是一个前台线程
2、前台线程是可以组织线程退出的
3、后台线程不阻止影响进程的退出
2.2、线程是否存活
/**
* 演示线程是否存活
*/
public class Exe_03 {
public static void main(String[] args) throws InterruptedException {
//创建线程
Thread thread=new Thread(()->{
int count=0;
while(true) {
System.out.println("小黑子" + count++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//运行五次退出
if(count>=5){
break;
}
}
});
//启动之前查看是否存活
System.out.println("启动之前是否存活->"+thread.isAlive());
//启动线程
thread.start();
//等待一秒让系统创建线程,确保线程创建完成开始执行
Thread.sleep(1000);
System.out.println("启动之后是否存活"+thread.isAlive());
//等待线程执行完成
thread.join();
System.out.println("线程执行完成是否存活"+thread.isAlive());
}
}
2.3、线程的各个属性
/**
* 线程的属性
*/
public class Exe_04 {
public static void main(String[] args) {
Thread thread=new Thread(()->{
while(true){
System.out.println("hello,iKun");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"鸽鸽");
//启动线程
thread.start();
System.out.println("线程id="+thread.getId());
System.out.println("线程名="+thread.getName());
System.out.println("进程状态="+thread.getState());
System.out.println("进程优先级="+thread.getPriority());
System.out.println("线程是否后台="+thread.isDaemon());
System.out.println("线程是否存活="+thread.isAlive());
System.out.println("线程是否中断="+thread.isInterrupted());
}
}
2.4、start()和run()方法的区别
分别调用这两个方法的现象?
start()方法:它调用系统API,去申请一个系统层面的PCB,也就是说真正的申请系统的线程。
run()方法:是在描述线程中具体要执行的任务。
*单独调用run方法,只是对一个普通的java对象的普通方法调用而已,跟String的equals()方法一样,它并没有真正的去启动一个线程。
/*
start()方法是真正意义上调用系统API,申请系统层面的PCB,申请了系统创建线程的资源,真正创建了线程,可以进行多线程的调用
run()描述了线程任务,并不能进行多线程的调用,就跟普通的方法是一样的
*/
public class Exe_05 {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
while(true){
System.out.println("只因坤坤爱坤坤");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
//调用run方法
thread.run();
//主线程打印一句话
while(true){
System.out.println("main");
Thread.sleep(1000);
}
}
}
2.5、线程中断
线程执行一半的时候需要停下来,提前结束。
目前常见的有以下两种方式:
1. 通过共享的标记来进行沟通
2. 通过thread调用 interrupted() 方法来通知
方式一:
/**
* 通过标志位完成线程中断
*/
public class Exe_06 {
//设置标志符
private static Boolean isQuit=false;
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(() ->{
//每次执行都要判断是否中断标志位
while(!isQuit){
System.out.println("再多一眼看一眼就会爆炸");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程执行完成");
});
System.out.println("线程启动前的状态="+thread.getState());
System.out.println("线程启动前是否存活="+thread.isAlive());
//启动线程
thread.start();
System.out.println("线程启动后的状态="+thread.getState());
System.out.println("线程启动后是否存活="+thread.isAlive());
//等待5秒
Thread.sleep(4000);
//修改标志位
isQuit=true;
Thread.sleep(4000);
System.out.println("线程中断之后的状态="+thread.getState());
System.out.println("线程中断之后是否存活="+thread.isAlive());
}
}
方式二:
public class Exe_07 {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(() ->{
//判断当前线程内部维护的中断标识
while(Thread.currentThread().isInterrupted()){
System.out.println("练习时长两年半");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//中断唤醒线程睡眠状态,会抛出异常
//处理中断逻辑
//方式一;什么也不干,不去理会
//方式二:一会处理
//方式三:真正的中断操作
break;
}
}
System.out.println("线程执行完成");
});
//启动线程
thread.start();
System.out.println("启动之前线程状态"+thread.getState());
System.out.println("启动之前是否存活"+thread.isAlive());
//先让这个线程执行一会
Thread.sleep(3000);
//中断线程
thread.isInterrupted();//调用本地方法让PCB完成中断
//等待线程销毁
Thread.sleep(3000);
System.out.println("中断之后线程状态"+thread.getState());
System.out.println("中断之后是否存活"+thread.isAlive());
}
}
调用Interrupted()方法后,会有两种情况注意:
1、线程正在RUNNABLE状态,那么不抛出异常,会直接中断。
2、线程在TIMED_WAITING状态,这时线程被唤醒配置并抛出异常,那么处理逻辑就要以catch语句块进行处理
3、处理中断能否正确执行,有两个地方需要判断,一个式while循环条件,处理情况1,异常中处理情况2。
2.6、线程等待
public class Exe_08 {
public static void main(String[] args) {
//创建线程
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("线程执行完成!");
});
//启动线程
thread.start();
System.out.println("join之前线程状态" + thread.getState());
System.out.println("join之前是否存活" + thread.isAlive());
//使用join等待thread线程结束
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("join之后线程状态" + thread.getState());
System.out.println("join之后是否存活" + thread.isAlive());
System.out.println("主线程执行完成!!");
}
}
2.7、休眠当前线程
2.8、获取当前线程
方法 | 说明 |
public static Thread currentThread(); | 返回当前线程对象的引用 |
3、线程的状态
线程的状态是一个枚举类型 Thread.State
*NEW: 安排了工作, 还未开始行动
*RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
*BLOCKED: 这几个都表示排队等着其他事情
*WAITING: 这几个都表示排队等着其他事情
*TIMED_WAITING: 这几个都表示排队等着其他事情
*TERMINATED: 工作完成了.