当前位置: 首页 > article >正文

别再犯这些Java并发编程的常见错误!你中了几个?

在这里插入图片描述

你好,我是忆~遂愿,全网2w+粉丝,《遂愿盈创》社群主理人。
副业启航① | 遂愿盈创(对副业感兴趣免费可入,多种赚钱实战项目等你来,一起探寻副业快速变现的途径;以及对接互联网大厂商务合作,一起来搞点小外快,认识更多互联网大咖)
目前群里已经带很多小伙伴(大部分大学生)变现几百块啦,程序员搞副业有额外加成~
对副业感兴趣可+V : suiyuan2ying 拉你进群。

文章目录

    • 1 什么是守护线程,它的使用场景是什么?如何创建守护线程 ?
    • 2 什么是 Thread 的中断标志?怎么设置和检查它?
    • 3 Thread 的中断标志与 InterruptedException 有什么关系?
    • 4 Object类的 wait,notify 和 notifyAll 方法的目的是什么 ?

1 什么是守护线程,它的使用场景是什么?如何创建守护线程 ?

想象一下,一个大型音乐会。音乐会的主要演出是乐队的表演,这就是主线程。乐队在舞台上演奏音乐,吸引观众的注意。舞台的清洁工则是后台支持人员,他们的工作是不断清理舞台上的杂物,确保乐队的演出能够顺利进行。清洁工并不要求乐队完成演出后再开始工作,而是随时在后台默默地工作。当音乐会结束时,清洁工也会跟着结束,不会再继续工作。

守护线程是指那些在后台运行,支持应用程序的主要任务的线程。它们的存在目的是提供必要的服务,比如垃圾回收或定时任务或定期清理缓存或监控系统状态,这些线程在应用程序的其他部分完成时会自动结束。

一个日志记录线程可以作为守护线程,在应用程序运行期间持续记录日志,而不会阻止应用程序的结束。

创建守护线程很简单,只需要设置线程的守护标志。在 Java 中,线程的守护状态通过 Thread.setDaemon(true) 方法设置。

public class DaemonThreadExample {
    public static void main(String[] args) {
        Thread daemonThread = new Thread(() -> {
            while (true) {
                // 会每秒打印一行信息
                System.out.println("守护线程正在运行...");
                try {
                    // 守护线程失眠 1 秒
                    Thread.sleep(1000); 
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        // 设置为守护线程
        daemonThread.setDaemon(true); 
        // 启动守护线程
        daemonThread.start(); 

        try {
            // 主线程休眠 5 秒
            Thread.sleep(5000); 
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 主线程睡眠 5 秒后结束,这时守护线程也会随着主线程的结束而终止
        System.out.println("主线程结束");
    }
}

2 什么是 Thread 的中断标志?怎么设置和检查它?

想象一下,一个工人在工地上忙碌地工作。他的任务是修建一条道路,工地上设有一个“停工指示牌”,这个指示牌用来告诉工人是否需要停下来并等待进一步的指示 ,当工人看到这个指示牌上写着“停工”时,他就知道需要暂时停止手头的工作。

线程的中断标志是一种机制,用于通知线程它应该停止当前的工作并退出,线程的中断标志并不直接终止线程,而是提供了一种与线程交互的方式,让线程可以在适当的时候响应终止请求。

每个线程都有一个中断标志,这个标志可以被设置、检查或清除。中断标志的状态可以通过两个主要的方法来操作:Thread.interrupt()Thread.isInterrupted()

线程的中断标志可以通过调用 Thread.interrupt() 方法设置,当这个方法被调用时,线程的中断标志被标记为 true

不过,仅仅设置中断标志并不会立即停止线程的执行,线程需要在自己的代码中定期检查中断标志,并做出响应。

Thread thread = new Thread(() -> {
    // 检查线程的中断标志
    while (!Thread.currentThread().isInterrupted()) {
        // 执行一些工作
        System.out.println("线程正在运行...");
        try {
            // 模拟工作
            Thread.sleep(1000); 
        } catch (InterruptedException e) {
            // 捕获到中断异常时,将线程的中断标志重新设置为 true
            Thread.currentThread().interrupt();
        }
    }
});

如果线程正在执行 Thread.sleep()Object.wait()Thread.join() 等方法时被中断,这些方法会抛出 InterruptedException 异常。

在捕获到这个异常后,应该重新设置中断标志,以确保中断信号能够被正确处理。这个动作通过 Thread.currentThread().interrupt() 方法完成。

要设置线程的中断标志,可以在其他线程中调用 Thread.interrupt() 方法。

Thread thread = new Thread(() -> {
    // 工作线程中的循环会因为 isInterrupted() 返回 true 而结束,从而使线程终止
    while (!Thread.currentThread().isInterrupted()) {
        System.out.println("线程正在运行...");
        try {
            // 线程被阻塞,等待 10 秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // 捕获到中断异常,线程被中断
            System.out.println("Thread was interrupted!");
            // 保持中断标志状态
            Thread.currentThread().interrupt(); 
        }
    }
});

thread.start();
try {
   // 让线程运行一段时间,然后中断它
   Thread.sleep(1000);
   thread.interrupt();
} catch (InterruptedException e) {
   e.printStackTrace();
}

3 Thread 的中断标志与 InterruptedException 有什么关系?

线程的中断标志与 InterruptedException 紧密相关,每个线程都有一个中断标志,用来指示线程是否应该停止当前的操作。当这个标志被设置为中断时,线程就会响应这个请求。

当线程执行一些可能会被中断的操作,比如 Thread.sleep()Object.wait()Thread.join() 时,它们会被阻塞。这时候,如果其他线程调用了 interrupt() 方法来中断这个线程,那么这些操作会抛出一个 InterruptedException,这是一个特殊的异常,表示线程在被中断的过程中被打断了。

抛出 InterruptedException 时,线程的中断标志会被清除,意味着线程已经知道中断发生了,但它需要处理这个异常,处理完成后,线程可以检查其中断标志,决定如何继续运行或者是否终止。

具体Demo如上2中所示

4 Object类的 wait,notify 和 notifyAll 方法的目的是什么 ?

Object 类的 waitnotifynotifyAll 方法用于线程间的协调和通信,这些方法通常在多线程编程中用于控制线程的执行顺序。

wait 方法使得调用它的线程进入等待状态,直到其他线程调用了 notifynotifyAll 方法,这个等待过程是有条件的,通常在线程需要等待某种条件发生时使用。使用 wait 方法的线程会释放它所持有的锁,从而允许其他线程获得这个锁并执行其操作。

notify 方法会唤醒在对象的监视器上等待的一个线程。如果有多个线程在等待同一个对象的监视器,notify 只会唤醒其中一个线程,但无法保证具体是哪一个线程;如果多个线程都在等待,则唤醒哪个线程是不确定的。

notifyAll 方法则会唤醒在对象的监视器上等待的所有线程。这意味着所有等待的线程都会被唤醒,然后争夺监视器的控制权,如果有多个线程在等待,则它们都会被唤醒,接下来所有被唤醒的线程会尝试重新获得锁,并继续执行。

展示了这些方法如何在实际应用中协作

public class SharedResource {
    private boolean condition = false;

    public synchronized void waitForCondition() {
        while (!condition) {
            try {
                // 进入等待状态,直到 condition 为 true
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        // 条件满足后继续执行
        System.out.println("Condition met, proceeding...");
    }

    public synchronized void setConditionTrue() {
        condition = true;
        // 通知等待中的线程条件已经满足
        notifyAll();
    }
}

public class Example {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        // 创建两个线程,它们将等待条件的变化
        Thread waiter1 = new Thread(() -> resource.waitForCondition());
        Thread waiter2 = new Thread(() -> resource.waitForCondition());

        waiter1.start();
        waiter2.start();

        try {
            // 主线程等待一段时间,然后设置条件为 true
            Thread.sleep(1000);
            resource.setConditionTrue();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

通过这种方式,可以实现线程之间的协调,使得一个线程可以通知其他线程某些条件已经发生,从而提高多线程程序的效率和协调性。

不要等待机会,而要创造机会


http://www.kler.cn/news/357694.html

相关文章:

  • Java-类与对象-下篇
  • mysql学习教程,从入门到精通,sql序列使用(45)
  • 红日安全vulnstack (一)
  • Redis应用高频面试题
  • 【VUE】封装用户树形选择和部门树形选择控件
  • 递归神经网络(RNN)简介
  • Docker无法拉取镜像解决办法
  • TiDB 关联子查询及半连接的优化实践
  • 微信小程序设计尺寸
  • 数据结构2-线性表
  • 富唯智能:重塑CNC格局,柔性制造开启智能制造新时代
  • 练习题 - Scrapy爬虫框架 Items 数据项
  • 【ARM】AMBA概述
  • 跟《经济学人》学英文:2024年10月19日这期 Pity the superstar fashion designer
  • 代码随想录算法训练营第三十六天|56. 合并区间,738. 单调递增的数字,968. 监控二叉树
  • 【OD】【E卷】【真题】【100分】流浪地球(PythonJavaJavaScriptC++C)
  • [论文笔记] Megatron LM环境安装
  • 如何查看默认网关地址:详细步骤
  • 高级大数据工程师带你一起学习Hdoop生态Flink基础原理保姆级教程
  • Docker 安装达梦 DM8 数据库实战指南