目录
一、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常见属性
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否有后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
getId(): ID是线程的唯一标识,不同的线程不重复
class MyThread extends Thread{@Overridepublic 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方法是否执行结束。
public static void main(String[] args) {Thread t = new MyThread();System.out.println(t.isAlive());t.start();System.out.println(t.isAlive());}
三、Thread常见方法
start()
start() 启动一个线程。
只有当start(),操作系统内核才会创建一个真真正正的线程PCB,然后去调用run()方法。
获取当前线程
方法 | 说明 |
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();t.join();System.out.println("Main!");}
如果去掉join()方法后,主线程与Thread线程抢占式执行!