一.Thread 类及常见方法
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联.
每个执行流,也需要有一个对象来描述,Thread 类的对象正是用来描述一个线程执行流的.JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理.
1.对线程重命名
public static void main(String[] args) {
Thread t1 = new Thread("线程一"){
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
System.out.println("嗨呀!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
System.out.println("盖亚!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"线程二");
t2.start();//新线程启动之后,就把 PCB 挂在链表上
//主线程
while(true){
try {
Thread.sleep(1000);
System.out.println("主线程...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上面的两个构造线程的方法,可以通过这两种方式对当前的线程命名.
2.通过控制台查看线程
1)找到 jdk 安装路径的bin目录
2)直接点击运行,如果不行则需要以管理员的身份运行,选择对应启动的类
3)查看线程
3.Thread 的几个常见属性
- getId():ID 是线程的唯一标识,不同线程不会重复
- getName():名称是各种调试工具会用到
- getState(): 状态标识线程当前所处的一个情况
- getPriority(): 优先级高的线程理论上来说更容易被调度到
- isDaemon()[是否后台线程]: JVM会在一个进程的所有非后台线程结束后,才会结束运行
- isAlive():是否存活,即简单的理解为,run方法是否运行结束了
判定当前内核中的 PCB 是否存在 - isInterrupted():线程是否被中断
4.中断线程
1)两种中断线程的方式:
目前常见的有以下两种方式:
- 通过共享的标记来进行沟通
- 调用 interrupt() 方法来通知
方式一:
private static volatile boolean flag = true;
public static void main(String[] args) {
Thread t = new Thread("线程一:"){
@Override
public void run() {
while(flag){
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" 正在工作中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("啊?好的,我停止工作了");
}
};
t.start();
try {
//3s 后让工作停止
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"(主线程):给我停止工作!");
flag = false;
}
方式二:
使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted()代替自定义标志位
Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// while(!Thread.currentThread().isInterrupted()){
while(!Thread.interrupted()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
System.out.println(Thread.currentThread().getName()+":正在工作中...");
}
System.out.println("啊?好的老板");
}
},"线程一");
t.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();//使用这个方法来通知线程结束
System.out.println(Thread.currentThread().getName()+":该结束工作了");
}
2)关于interrupt():
3)关于判断线程的标记位
静态的interrupted(): 判断当前线程的中断标志是否设置,调用(通过interrupt()修改标记位)后清除标记位;
非静态的isInterruped():判断对象关联的线程的标志位而是否设置,调用后不清除标志位
public static void main(String[] args) {
Thread t = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("非静态的标记位调用(修改标记后)后不清除标记:"+Thread.currentThread().isInterrupted());
}
});
t.start();
t.interrupt();
}
//得到的结果全为true,因为默认是false,修改后就变成了true了
public static void main(String[] args) {
Thread t = new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println("静态的标记位,调用后清楚标记:"+Thread.interrupted());
}
});
t.start();
t.interrupt();
}
//得到的先是true,后边反弹又变回false了
//调用interrupt()方法后,对标记位进行修改,返回true,又改回false了(标记)
5.等待线程join()
Thread.currentThread().join();//即等待这个线程里的任务全都完成,否则一直会阻塞等待
6.获取当前线程的引用
Thread.currentThread();
7.休眠当前线程
Thread.sleep(1000);//单位是ms,也就是等待这个线程1s
二.线程的状态
- NEW: 对象创建出来了,但是内核的 PCB 还没创建出来
- RUNNABLE: 可运行的(工作),当前的 PCB 也创建出来了.同时这个 PCB 随时待命(就绪队列).这个线程可能是正在 CPU 上运行,也可能是在就绪队列中排队
- TIMED_WAITING:表示当前的 PCB 在阻塞队列中等待,这样的等待是一个"带有时间结束"的等待.Thread.sleep(3000);
- WAITING:线程中如果调用了 wait 方法,也会阻塞等待,此时处在 WAITING 状态.(死等)除非是其他线程唤醒了该线程.
- BLOCKED: 线程中尝试进行加锁,如果发现锁已经被其他线程占用了.此时该线程也会阻塞等待,这个等待就会在其他线程释放锁之后,被唤醒.
- TERMINATED: 表示当前 PCB 已经结束了.Thread 对象还在,此时获取状态,得到的就是此状态.