文章目录
- 一、Thread常见构造方法
- 二、Thread常见属性
- 三、Thread常见方法
- start()
- 获取当前线程
- 休眠当前线程
- 中断线程
- join()
一、Thread常见构造方法
Thread类是JVM用来管理线程的一个类,每个线程都有唯一一个Thread对象与之对应,JVM会将这些对象组织起来,线程调度,线程管理。
方法 | 说明 |
---|---|
Thread() | 创建线程对象 |
Thread(Runnable target | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target,String name) | 使用Runnable对象创建线程,并命名 |
我们在创建Thread的对象为什么要命名?方便我们查看信息和调试。
线程默认名叫做Thread-0, Thread-1等等,当线程比较多的时候,很难分辨线程,所以我们可以命名。
二、Thread常见属性
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否有后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
getId(): ID是线程的唯一标识,不同的线程不重复
class MyThread extends Thread{
@Override
public void run() {
System.out.println("Hello world!");
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getId());
}
}
getName: 名称是我们构造方法设置的名称,如果没有设置,那就是默认名。
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getName());
}
因为我们没有命名,所以使用的是默认名。
getState(): 指的是当前线程所处的状态 ( java当中的线程状态比操作系统中的状态更丰富,分的更细 ).
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getState());
}
这里NEW状态 (指的是线程对象已创建,但操作系统还没有为其分配PCB) 是什么大家先不用管,后面我们会详细介绍,只需要知道getState()方法是用来查看线程状态的。
getPriority: 我们可以获取当前线程的优先级,但没有太大的用,实际还得取决于操作系统内核的具体调度。
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getPriority());
}
isDaemon(): 是否为守护线程(也叫后台线程), 简单的理解一下,我们手动创建的线程都是前台线程,JVM自带的线程都是后台线程,我们也可以通过setDaemon()方法将前台线程设置为后台线程。
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.isDaemon());
}
isAlive(): 线程的run方法是否执行结束。
如果我们只创建了一个t变量,我们并没有在操作系统内核里有线程,只是把我们线程执行的任务梳理好了
当我们执行了start()方法后,就会让内核创建一个PCB,此时这个PCB才表示一个真正的线程。
调用start()方法之前,isAlive()是false
调用start()方法之后,run()方法未执行完,isAlive()为false.
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.isAlive());
t.start();
System.out.println(t.isAlive());
}
**isInterrupt(): ** 线程中断问题
这两个方法我们后面会进一步说明。
三、Thread常见方法
start()
start() 启动一个线程。
class MyThread extends Thread{
@Override
public void run() {
System.out.println("Hello world!");
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
}
run()方法提供线程要做的事情的指令清单。
这是创建t对象,只是知道要找那样的线程做什么事
只有当start(),操作系统内核才会创建一个真真正正的线程PCB,然后去调用run()方法。
获取当前线程
方法 | 说明 |
---|---|
currentThread() | 获取当前线程对象的引用 |
我们可以发现currentThread()方法是Thread类下的一个静态方法,所以我们直接使用类名调用即可。
休眠当前线程
方法 | 说明 |
---|---|
sleep(long millis) | 休眠当前线程millis毫秒 |
由于线程调度是不可控的,我们sleep()方法的实际休眠是大于等于设置的时间的。
我们的sleep方法也是Thread下的静态方法,直接类名调用即可。
需要注意的是我们在那个线程下面调用该方法,那个线程休眠。
使用sleep时会有一个中断异常(非受查异常),需要我们手动抛出。
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(System.currentTimeMillis());
}
我们直接在主线程演示一下该方法。
中断线程
线程中断: 我们这里的中断,并不是线程立即就结束了,而是通知该线程,你应该结束了,但实际是否结束,取决于线程里具体的代码。
1.使用标志位来控制线程是否结束
public class ThreadDemo {
private static boolean flg = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (flg) {
System.out.println("My Thread!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(3000);
flg = false;
}
}
我们这个代码之所以能够起到修改flg就使线程结束,完全取决于线程内部的代码书写,我们只能起到一个通知作用,至于是否结束,还是取决于线程内部,即使我们sleep正在休眠,我们的标志位也可以唤醒sleep。
2. 调用 interrupt() 方法来通知
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("My Thread!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(3000);
t.interrupt();
}
我们可以发现我们的代码触发了异常。
在唤醒sleep之后,我们的线程还在一直执行
interrupt()方法会做两件事:
1.把线程内部的标志位设置为true
2.如果线程正在sleep,会触发异常,将sleep唤醒。
sleep唤醒的同时,会清空标志位,将刚才设置的标志位在设置为false(这就导致,我们的循环会继续执行).
如果我们想去中断,我们可以在异常里加一个break。当我们sleep被唤醒时,结束run()方法。
这里再一次证明了,这里的中断只是通知线程,至于是否执行还得看线程内部的代码。
join()
join(): 等待一个线程
因为我们线程是随即调度的过程,线程的执行顺便我们无法把控,但在一些场景下我们需要有明确的线程程序顺序,等待线程,就是可以控制两个线程的结束顺序。
方法 | 说明 |
---|---|
join() | 等待线程结束 |
join(long millis) | 等待线程结束,最多等millis毫秒 |
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("My Thread!");
}
});
t.start();
System.out.println("Main!");
}
我们想让t线程先执行完,再去打印Main!
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("My Thread!");
}
});
t.start();
t.join();
System.out.println("Main!");
}
我们在主线程调用了下join()方法。