如何创建线程
创建线程的两种方式:继承Tread类,实现Runnable接口
继承Thread类
需要基层Thread类,并重写run方法,run方法里的内容就是线程需要执行的。
然后调用t.start()方法来开启这个线程。
public class Test_1 extends Thread {
@Override
public void run() {
System.out.println("abcde");
}
public static void main(String[] args) {
Thread t = new Test_1();
t.start();
}
}
运行结果如下, 可以看到成功执行了run方法中的代码
abcde
Process finished with exit code 0
实现Runnable接口(建议使用这种方式)
如下所示,显示Runnable接口,并实现run方法。run方法里的内容就是线程需要执行的。
在创建Thread对象时,把实现Runnable接口的实例传进去,然后使用 t.start();开始线程。
public class Test_2 implements Runnable {
@Override
public void run() {
System.out.println("abcde");
}
public static void main(String[] args) {
Thread t = new Thread(new Test_2());
t.start();
}
}
运行结果如下, 可以看到成功执行了run方法中的代码
abcde
Process finished with exit code 0
建议使用这种方式来创建线程。因为与继承相比,实现接口的方式耦合度更低,扩展性更高。
使用sleep方法暂停线程的执行
Thread类提供了静态方法sleep来挂起线程一段时间,挂起线程的时间精确到纳秒级
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException
测试代码如下, 创建一个线程,每一秒打印依次当前时间,需要注意的时当线程在被挂起时,可能会被其他线程中断并抛出InterruptedException异常,所以我们要在这里处理下这个异常
public class Test_3 implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println(System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread t = new Thread(new Test_3());
System.out.println(System.currentTimeMillis());
t.start();
}
}
运行结果如下
1600326668837
1600326669853
1600326670858
1600326671862
1600326672864
1600326673874
1600326674878
1600326675882
1600326676887
1600326677893
1600326678907
Process finished with exit code 0
中断(Interrupt)
中断用来告诉线程,他应该停下当先的工作,去做别的事情。通常用来终止线程的运行。
就好比你上课再睡觉,突然老师点你的名字了,就相当与老师这个线程给中断了正在睡觉的你,这个时候,你就应该停止睡觉,去回应老师了。
中断的核心方法如下:
public void interrupt(); // 中断调用这个方法的线程
public boolean isInterrupted(); // 返会调用这个方法的线程的中断的状态
public static boolean interrupted() // 返会当前线程是的中断的状态,如果是true, 就置为false
如何产生一个中断
在上面测试sleep的代码里,我们在在调用sleep方法是捕获了一个InterruptedException,这个异常就是当线程挂起并被中断时抛出的。
下是一个线程被挂起之后中断它的例子。
public class Test_4 implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println(System.currentTimeMillis());
}
} catch (InterruptedException e) {
System.out.println("被中断啦!!!");
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Test_4());
System.out.println(System.currentTimeMillis());
t.start();
Thread.sleep(3000);
t.interrupt(); // 中断线程
}
}
运行结果如下
1600330453677
1600330454687
1600330455688
1600330456692
被中断啦!!!
Process finished with exit code 0
如何获取中断状态
获取中断状态的两个方法如下
public boolean isInterrupted(); // 返会调用这个方法的线程的中断的状态
public static boolean interrupted() // 返会当前线程是的中断的状态,如果是true, 就置为false
public boolean isInterrupted()
测试代码如下。先创建一个线程。3s之后然后中断他,然后通过isInterrupted查询这个线程的中断状态,3s之后再通过isInterrupted查询这个线程的中断状态
public class Test_5 implements Runnable {
@Override
public void run() {
while (true) {
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Test_5());
t.start();
System.out.println("t.isInterrupted() = " + t.isInterrupted());
Thread.sleep(3000);
t.interrupt();
System.out.println("t.isInterrupted() = " + t.isInterrupted());
Thread.sleep(3000);
System.out.println("t.isInterrupted() = " + t.isInterrupted());
}
}
运行结果如下。中断之前,线程的中断状态时FALSE,中断之后会是TRUE,调用isInterrupted()不会改变该线程的中断状态
t.isInterrupted() = false
t.isInterrupted() = true
t.isInterrupted() = true
Process finished with exit code -1
这个API通常用来查询其他线程的中断状态
public static boolean interrupted()
测试代码如下。创建一个线程,在该线程中不断使用Thread.interrupted()查询中断状态。然后启动这个线程,3s之后中断它,3s之后查询这个线程的中断状态
public class Test_6 implements Runnable {
@Override
public void run() {
while (true) {
if(Thread.interrupted()) {
System.out.println("被中断了!!!");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Test_6());
t.start();
System.out.println("t.isInterrupted() = " + t.isInterrupted());
Thread.sleep(3000);
t.interrupt();
Thread.sleep(3000);
System.out.println("t.isInterrupted() = " + t.isInterrupted());
}
}
运行结果如下, 可以看到在线程中调用Thread.interrupted()拿到中断状态为TRUE,并打印出消息之后,使用t.isInterrupted()再拿到的中断状态是FALSE,说明中断状态被重置了
t.isInterrupted() = false
被中断了!!!
t.isInterrupted() = false
这个方法通常用来拿当前线程的中断状态
等待其他线程执行完毕的方法join
public final void join() throws InterruptedException // 等待调用此方法的Thread对象的代表的线程结束
使用方法如下:
public class Test_7 implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println(System.currentTimeMillis());
}
} catch (InterruptedException e) {
System.out.println("被中断啦!!!");
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Test_7());
t.start();
t.join(); // 等待线程t结束
System.out.println("t stop");
}
}
先再main方法中创建一个线程t,此时main方法所属的线程和线程t是两个不同的线程,
然后调用t.join让main方法所属的线程等待线程t结束
运行结果如下
1600333074573
1600333075587
1600333076598
1600333077612
1600333078619
1600333079633
1600333080637
1600333081653
1600333082657
1600333083662
t stop
Process finished with exit code 0