简明易懂多线程(二) JAVA

文章介绍了Java中多线程的中断机制,包括interrupt()方法的使用、isInterrupted()检查、join()方法的行为,以及守护线程的概念和创建方法。还讨论了volatile关键字在确保线程间共享变量可见性的重要性。
摘要由CSDN通过智能技术生成

多线程(一)
多线程(二)
多线程(三)

中断线程

  • 调用interrupt()方法中断线程

在其他线程中对目标线程调用interrupt方法,目标线程需要反复检测自身状态是否是interruptted状态,如果是就立刻结束运行

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1); // 暂停1毫秒
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        System.out.println("end");
    }
}

class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (! isInterrupted()) {
            n ++;
            System.out.println(n + " hello!");
        }
    }
}

在上述代码中,main线程通过对t线程调用interrupt()方法中断线程t,但要特别注意的是,interrupt()方法仅仅是发出来"中断请求",具体能否响应中断,还是要看具体代码
如上述代码中while循环会检查isInterrupted()状态,在响应后”interrupt请求“后能使得run()立即结束

再看下面一段代码

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1000);
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        System.out.println("end");
    }
}

class MyThread extends Thread {
    public void run() {
        Thread hello = new HelloThread();
        hello.start(); // 启动hello线程
        try {
            hello.join(); // 等待hello线程结束
        } catch (InterruptedException e) {
            System.out.println("interrupted!");
        }
        hello.interrupt();
    }
}

class HelloThread extends Thread {
    public void run() {
        int n = 0;
        while (!isInterrupted()) {
            n++;
            System.out.println(n + " hello!");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}

如果线程处于等待状态,例如,t.join()会让main线程进入等待状态,此时,如果main线程中对线程t调用interrupt(),join()方法会立刻抛出InterruptedException,因此,目标线程只要捕获到join()方法抛出的InterruptedException,就说明有其他线程对其调用了interrupt()方法,通常情况下该线程应该立刻结束运行。
在t线程结束前,对hello线程也进行了interrupt()调用通知其中断。如果去掉这一行代码,可以发现hello线程仍然会继续运行,且JVM不会退出。

  • 设置标志位中断线程

另一个常用的中断线程的方法是设置标志位。我们通常会用一个running标志位来标识线程是否应该继续运行,在外部线程中,通过把HelloThread.running置为false,就可以让线程结束:

public class Main {
    public static void main(String[] args)  throws InterruptedException {
        HelloThread t = new HelloThread();
        t.start();
        Thread.sleep(1);
        t.running = false; // 标志位置为false
    }
}

class HelloThread extends Thread {
    public volatile boolean running = true;
    public void run() {
        int n = 0;
        while (running) {
            n ++;
            System.out.println(n + " hello!");
        }
        System.out.println("end!");
    }
}

helloThred的标志位running是一个线程间共享的变量,用关键字volatile修饰。

为什么要用volatile关键字呢?
这与JAVA的内存模型相关。在JVM虚拟机中,变量的值保存在主内存中,当线程访问变量时,它会先获取一个副本,并保存在线程的工作内存中,如果修改了变量的值,JVM会在某个时刻把修改后的值写回到主内存,但这个时刻是不确定的
如果不用volatile关键字就可能会导致各个线程中变量的值并不相同,
因此使用volatile关键字是告诉虚拟机:

  • 每次访问变量时,总是获取主内存中最新的值;
  • 每次修改变量后,总是立刻写回主内存;
    volatile解决的是可见性问题:当一个线程修改了某个共享变量的值后,其他线程能立刻看到修改后的值。

守护线程

Java程序的入口是由JVM启动main线程,只有当main线程以及main中启动的其他线程都结束时,JVM才会退出,程序才会结束。
但如果有些线程的目的就是无限循环,例如,定时触发任务的线程,如果这个线程不结束,那么JVM就一直不会退出。
为了解决这种问题,我们需要引入守护线程
守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,JVM都会退出。

创建守护线程

Thread t = new MyThread();
t.setDaemon(true);
t.start();

创建守护线程的方法和创建普通线程基本一样,只是需要在启动线程前加上t.setDaemon(true);
特别注意守护线程不能持有任何需要关闭的资源,例如打开的文件等,因为JVM退出时,守护线程没有机会关闭文件,这会导致数据丢失。

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值