如何创建线程

创建线程的两种方式:继承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