JAVA中多线程

我们可以先来看一幅图,多线程就算围绕这幅图展开的。
在这里插入图片描述

1. 进程与线程的概念

进程:操作系统中一个程序的执行周期。
线程:一个线程同时执行多个任务。通常来讲,每一个任务就称为一个线程。
进程与线程比较

  1. 与进程相比,线程更加“轻量级”,创建、撤销一个线程比启动、撤销一个进程开销要小的多。一个进程中的所有线程共享此进程的所有资源。
  2. 没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。
  3. 进程是操作系统资源调度的基本单位,进程可以独享资源,线程需要依托进程提供的资源,无法独立申请操作系统资源,是操作系统任务执行的基本单位。

2. Java多线程实现

2.1 继承Thread类实现多线程
java.lang.Thread是线程操作的核心类。新建一个线程最简单的方法就是直接继承Thread,而后覆写run()方法(相当于主线程的main()方法)。
例:

package www.java.test;

class MyThread extends Thread{//新建一个线程直接继承Thread
    private String title;

    public MyThread(String title) {
        this.title = title;
    }

    @Override
    public void run() {//覆写run()方法
        for(int i = 0; i < 10; i++){
            System.out.println(this.title+",i = "+i);
        }
    }
}

public class Test{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        myThread1.run();;
        myThread2.run();
        myThread3.run();
    }
}

我们很容易联想到,既然覆写的是run()方法,那是不是调用run()方法来启动多线程呢?
结果:
在这里插入图片描述
我们发现结果是顺序的,并没有启动多线程。
再看看下边这段代码:

package www.java.test;

class MyThread extends Thread{//新建一个线程直接继承Thread
    private String title;

    public MyThread(String title) {
        this.title = title;
    }

    @Override
    public void run() {//覆写run()方法
        for(int i = 0; i < 10; i++){
            System.out.println(this.title+",i = "+i);
        }
    }
}

public class Test{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        myThread1.start();;
        myThread2.start();
        myThread3.start();
    }
}

在这里插入图片描述
多个线程交替出现,说明实现了多线程。
其实调用start()最终的目的也是为了调用run()方法,那为什么不直接调用run(),而是通过start()来调用run()呢?
我们可以查看start()源码,就可以总结出java线程创建的流程:start(Java方法)–>start0(JVM)–>进行资源调度,系统分配(JVM)–>run(Java方法)执行线程的具体操作任务

总结:无论那种方式实现多线程,线程启动一定调用Thread类提供的start()方法。
每一个线程start()方法只能调用一次,多次调用会出现异常(java.lang.IllegalThreadStateException)。
2.2 实现Runnable接口来实现多线程
使用Runnable接口虽然解决了单继承局限问题,但接口中是没有start()方法的,该如何启动多线程呢?
Thread类有一个构造函数是这样的public Thread(Runnable target),可以接收一个Runnable对象。我们只需要把Runnable对象传进去,然后再调用start()方法就可以启动多线程了。
例:

package www.java.test;

class MyThread implements Runnable{//新建一个线程直接继承Thread
    private String title;

    public MyThread(String title) {
        this.title = title;
    }

    @Override
    public void run() {//覆写run()方法
        for(int i = 0; i < 10; i++){
            System.out.println(this.title+",i = "+i);
        }
    }
}

public class Test{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        new Thread(myThread1).start();
        new Thread(myThread2).start();
        new Thread(myThread3).start();
    }
}

在这里插入图片描述
使用Lamdba表达式进行Runnable对象创建:

package www.java.test;

public class Test{
    public static void main(String[] args){
        Runnable runnable = ()-> System.out.println("hello world");
        new Thread(runnable).start();
    }
}

使用匿名内部类实现Runnable对象创建:

package www.java.test;

public class Test{
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        }).start();
    }
}

2.3 继承Thread类与实现Runnable接口的关系

  1. Thread类与自定义线程类(实现了Runnable接口),是一个典型的代理设计模式。Thread类负责辅助真实业务操作(资源调度,创建线程并启动),自定义线程类负责真实业务的实现(run()方法具体要做什么)。
  2. 使用Runnable接口实现的多线程程序类可以更好的描述共享的概念。

使用Thread类实现数据共享:

package www.java.test;

class MyThread extends Thread{
    private int ticket = 10;
    @Override
    public void run() {
        while(this.ticket > 0){
            System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket--);
        }
    }
}

public class Test{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

在这里插入图片描述
通过输出结果我们可以发现,三个线程各自卖各自的,并没有实现数据共享。

使用Runnable实现多线程:

package www.java.test;

class MyThread implements Runnable{
    private int ticket = 10;
    @Override
    public void run() {
        while(this.ticket > 0){
            System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket--);
        }
    }
}

public class Test{
    public static void main(String[] args){
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

在这里插入图片描述
2.4 实现Callable实现多线程—当线程有返回值时,只能用Callable实现多线程
在juc包中,是JDK-1.5新增的开发程序编程包

实现Callable接口,而后覆写call()方法,有返回值:

V call() throws Exception;
Future<v> 接口:取得Callable接口的返回值
v get() throws InterruptedException,ExecutionException;

例:

package www.java.test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyThread implements Callable<String> {
    private int ticket = 10;
    @Override
    public String call() throws Exception {
        while(this.ticket > 0){
            System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket--);
        }
        return "不好意思,票卖完了";
    }
}

public class Test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<>(new MyThread());
        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();
        System.out.println(task.get());
    }
}

在这里插入图片描述

3. 多线程常用操作方法

3.1 线程命名与取得

  1. 通过构造方法在创建线程时设置名称
public Thread(String name)
public Thread(Runnable target, String name)
  1. 取得线程名称
public final String getName()
  1. 创建线程后,设置线程名称
public final synchronized void setName(String name)

3.2 线程休眠方法sleep()----单位为毫秒
线程休眠:让当前线程暂缓执行,等到了预计时间后再恢复执行。
线程休眠会交出cpu,但不会释放锁。

public static native void sleep(long mills) throws InterruptedException;

例:

package www.java.test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("当前线程:"+Thread.currentThread().getName()+",i = "+i);
        }
    }
}

public class Test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

在这里插入图片描述
我们可以让程序跑起来,观察它的输出情况,或许会给我们一种错觉,就算三个线程是同时休眠的,但所有代码都是依次进入run()的。
我们还会发现打印速度是不同的,那是因为线程休眠会立马交出cpu,但不知道什么时候回来,cpu输出时间不定,打印速度不同,是因为获取cpu是随机的,时间不均匀,但休眠时间是相同的。
我们可以来验证一下它到底是不是立马交出CPU,我们可以同时启动3个线程,然后观察打印结果。

package www.java.test;
class MyThread implements Runnable{

    @Override
    public void run() {
        for(int i=0; i<3; i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Test{
    public static void main(String[] args){
        MyThread mt = new MyThread();
        new Thread(mt,"A").start();
        new Thread(mt,"B").start();
        new Thread(mt,"C").start();
    }
}

在这里插入图片描述
会发现,三个线程是交替出现的。这就说明它是立马交出CPU的。
3.3 线程让步(yield()方法)
暂停执行当前的线程对象,并执行其他线程。
yield()方法会让当前线程交出cpu,同样不会释放锁。但是yield()方法无法控制具体交出cpu的时间,并且yield()方法只能让拥有相同优先级的线程有获取cpu的机会。
例:

package www.java.test;

import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            Thread.yield();
            System.out.println("当前线程:" + Thread.currentThread().getName() + ",i = " + i);
        }
    }
}

public class Test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        new Thread(myThread).start();
        new Thread(myThread).start();
    }
}

在这里插入图片描述
可以来证明一下yield()不是立马交出CPU,只需要把上边证明sleep()的代码该一下就行,然后观察输出。

package www.java.test;
class MyThread implements Runnable{

    @Override
    public void run() {
        for(int i=0; i<3; i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
            Thread.yield();
        }
    }
}
public class Test{
    public static void main(String[] args){
        MyThread mt = new MyThread();
        new Thread(mt,"A").start();
        new Thread(mt,"B").start();
        new Thread(mt,"C").start();
    }
}

在这里插入图片描述
注意看输出结果,我们会发现A线程都执行完了才交出CPU,这就说明它并没有立即交出CPU,它还一直占有着CPU。
3.4 join()方法—等待其他线程终止
等待该线程终止。如果在主线程中调用该方法,会让主线程休眠,让调用该方法的线程先执行完毕再恢复执行主线程。
会释放锁
join()方法只是对Object提供的wait()做了一层包装而已。

我们可以先通过两段代码的对比来看join()方法的功能。

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i < 3; i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
        }
    }
}

public class Test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程开始");
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        System.out.println("主线程结束");
    }
    public static void printTime(){
        Date date=new Date();
        DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time=format.format(date);
        System.out.println(time);
    }
}

在这里插入图片描述
通过输出结果我们可以发现:子线程还没执行完主线程就已经执行完毕,主线程的结束不一定在子线程之后。表明主线程和子线程是一块走的。

我们现在调用join()方法来观察输出:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println("主线程休眠开始");
        Test.printTime();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程休眠结束");
        Test.printTime();
    }
}

public class Test{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程开始");
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        thread.join();
        System.out.println("主线程结束");
    }
    public static void printTime(){
        Date date=new Date();
        DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time=format.format(date);
        System.out.println(time);
    }
}

在这里插入图片描述
会发现:在主线程中,子线程调用了join()方法后,会一直等到子线程的run()方法执行完之后,才会继续执行主线程。
3.5 线程停止(手工停止)
子线程正常停止是子线程的run()方法执行完,所有的代码执行完,线程就停止了。

3.5.1 设置标记位停止线程
例:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        while(flag){
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
    }
    public void setFlag(boolean flag){
        this.flag = flag;
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(5000);
        myThread.setFlag(false);
    }
}

在这里插入图片描述
我们可以看到子线程执行了5次之后就停止了,那是因为主线程休眠了5秒之后,手动设置标志位把子线程停止了。
3.5.2 调用Thread类的stop()方法强制停止线程,该方法不安全,已经被废弃。
例:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        while(flag){
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
    }
    public void setFlag(boolean flag){
        this.flag = flag;
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(5000);
        thread.stop();
    }
}

在这里插入图片描述
它也可以停止线程,但为什么说它不安全呢?
如果while()循环里的语句是这样的:

while(flag){
	int x = 10;
	int y = 20;
}

如果采用第一种方法停止线程,一旦进入while循环,它就会等x和y全部赋值完毕才会停止;但如果采用stop()停止线程,如果是在x = 10与y = 20之间调用的,则会强制停止,这样y就没有被赋值,就产生了废弃数据。
3.5.3 调用Thread类的interrupt()方法
interrupt()方法只是将线程状态置为中断状态而已,它不会中断一个正在运行的线程。此方法只是给线程传递一个中断信号,程序可以根据此信号来判断是否需要终止。
例:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        int i = 1;
        while(true){
            boolean bool = Thread.currentThread().isInterrupted();
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
            System.out.println(bool);
            i++;
        }
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
    }
}

我们可以观察输出,前3秒的时候,bool的值都是false,后边bool的值一直都是true,因为调用了interrupt(),但子线程并没有停止,它一直在执行。所以它只是把这个状态置为了true,如果要想停止子线程,就要根据这个状态来做相应的操作。
用intrerrupt()退出线程:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        int i = 1;
        while(true){
            boolean bool = Thread.currentThread().isInterrupted();
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
            System.out.println(bool);
            if(bool){
                System.out.println("线程退出");
                break;
            }
            i++;
        }
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
    }
}

在这里插入图片描述
我们可以看到第一个true的时候,线程就退出了。这就和第一种方法一样,只不过第一种方法是自己设置一个标记位,而interrupt()是系统设置一个标记位。

但它有一个特殊点就是:当线程中使用了wait、sleep、join导致线程阻塞,则interrupt()方法会在线程中抛出InterruptedException,并且将线程的中断状态由true置为false。
我们可以看看这段代码的输出:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        int i = 1;
        while(true){
            boolean bool = Thread.currentThread().isInterrupted();
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
            System.out.println(bool);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(bool){
                System.out.println("线程退出");
                break;
            }
            i++;
        }
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
    }
}

在这里插入图片描述
我们看到在3秒之后,调用了interrupt()是抛了一个异常,但它并没有停止子线程,并且bool的值被改为了false。

我们到底怎样做才能用interrupt()来停止线程呢?看下边这段代码:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        int i = 1;
        while(true){
            try {
                boolean bool = Thread.currentThread().isInterrupted();
                System.out.println(Thread.currentThread().getName()+"第"+i+"次执行");
                System.out.println(bool);
                if(bool){
                    System.out.println("线程退出");
                }
                i++;
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("异常抛出,线程停止");
                Boolean bool = Thread.currentThread().isInterrupted();
                System.out.println("Catch块中的中断状态为"+bool);
                return;
            }
        }
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
    }
}

在这里插入图片描述
当线程中用了sleep,它就会抛出异常,能进入catch块就说明一定调用了interrupt(),我们可以在catch块中来进行线程终止,直接让它return就行。但会发现,它的状态标志一直都是false。
3.6 线程优先级(1-10)
线程优先级是指优先级越高越有可能先执行,但仅仅是有可能而已。

设置优先级

public final void setPriority(int newPriority)

取得优先级

public final int getPriority()

Thread类中有3个常量来判断最小优先级、中等优先级和最高优先级分别是:

MAX_PRIORITY = 10;
NORM_PRIORITY = 5;
MIN_PRIORITY = 1;

例:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
        }
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread,"子线程A");
        Thread thread2 = new Thread(myThread,"子线程B");
        Thread thread3 = new Thread(myThread,"子线程C");
        thread3.setPriority(Thread.MAX_PRIORITY);
        thread2.setPriority(Thread.NORM_PRIORITY);
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

我们在设置优先级的时候,子线程C的优先级最高,下来是B,最后是A,我们现在来看看输出结果。
在这里插入图片描述
发现并不设置的优先级最高它就先执行,设置优先级只是建议系统先执行哪个,但具体执行哪个是有系统决定的。

我们可以观察一下主线程的优先级:

public class Test{
    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
    }
}

在这里插入图片描述
所以主线程只是一个普通优先级而已。

线程具有继承性,只是继承优先级而已。
从A线程启动B线程,则B和A线程的优先级是一样的。
例:主线程的优先级是5,那如果在主线程中启动一个子线程,那么这个子线程的优先级和主线程的优先级一样都是5。

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
        new Thread(new MyThread(),"子线程A").start();
    }
}

在这里插入图片描述
我们可以再看一个例子:

package www.java.test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutionException;

class A implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
    }
}

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
        new Thread(new A(),"孙子线程B").start();
    }
}

public class Test{
    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"、"+Thread.currentThread().getPriority());
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程A");
        thread.setPriority(10);
        thread.start();
    }
}

在这里插入图片描述
由于B线程是在A线程中启动的,所以B和A的优先级一样。
3.7 守护线程
守护线程是一种特殊的线程,又称为陪伴线程。java中一共有两种线程:用户线程和守护线程。
Thread类提供isDaemon()区别两种线程:返回false表示该线程为用户线程;否则为守护线程。典型的守护线程就是垃圾回收线程。主线程main是用户线程。
例:

package www.java.test;

class A implements Runnable {
    private int i;
    @Override
    public void run() {
        try {
            while (true) {
                i++;
                System.out.println("线程名称:" + Thread.currentThread().getName() + ",i=" + i +
                        ",是否为守护线程:"
                        + Thread.currentThread().isDaemon());
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + "中断线程了");
        }
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new A(),"子线程A");
        // 设置线程A为守护线程,此语句必须在start方法之前执行
        thread1.setDaemon(true);
        thread1.start();
        Thread thread2 = new Thread(new A(),"子线程B");
        thread2.start();
        Thread.sleep(3000);
        // 中断非守护线程
        thread2.interrupt();
        Thread.sleep(10000);
        System.out.println("代码结束");
    }
}

在这里插入图片描述
我们提供输出结果可以发现,当用户线程B被中断后,守护线程并没有停止,因为主线程还没有结束,所以说明只有当所有用户线程都结束之后,守护线程才会结束。

猜你喜欢

转载自blog.csdn.net/huaijiu123/article/details/84964515