关于Java多线程的一些随笔

Synchronized与ReentrantLock有哪些相同点和不同点?

在Java中,synchronized关键字和ReentrantLock类都用于管理线程间的同步,但它们在实现方式、功能和灵活性方面存在一些差异。以下是它们的相同点和不同点:

相同点

  1. 互斥性synchronizedReentrantLock都提供了线程互斥的机制,确保在同一时间只有一个线程可以执行特定代码段。

  2. 防止线程干扰:它们都用于解决线程安全问题,避免多线程环境下的数据不一致性和竞争条件。

  3. 可重入性:这两种机制都是可重入的,即同一个线程可以多次获取已经持有的锁。

  4. 锁定代码块或对象:它们都可以锁定代码块或整个方法,以保护关键部分的代码不被多线程同时执行。

不同点

  1. 实现方式

    • synchronized是Java的内置关键字,其实现是隐藏的,用户无需手动管理锁的获取和释放。
    • ReentrantLock是Java标准库中的API,需要显式地创建锁对象,显式地获取和释放锁。
  2. 功能特性

    • ReentrantLock提供了比synchronized更多的功能,如可中断的锁获取、尝试非阻塞地获取锁(tryLock())、设置公平锁等。
    • synchronized不支持这些高级特性。
  3. 条件变量

    • ReentrantLockCondition对象配合,可以分别控制线程的等待和唤醒,这为线程间通信提供了更多的灵活性。
    • synchronized则是配合Object类的wait()notify()notifyAll()方法来实现线程间的通信。
  4. 锁的公平性

    • ReentrantLock允许用户选择是使用公平锁还是非公平锁。
    • synchronized不保证公平性,没有提供公平锁的选项。
  5. 性能和优化

    • 在Java 6及以后版本中,synchronized的性能得到了显著提升,尤其在低至中等线程竞争的情况下。
    • ReentrantLock可能在高竞争环境下表现更优,特别是在使用公平锁或者需要更复杂的条件同步时。
  6. 锁的可中断性

    • ReentrantLock允许在等待锁的过程中响应中断。
    • synchronized块内的线程等待获得锁时不能被中断。
总结

虽然synchronizedReentrantLock都用于实现线程同步,但ReentrantLock提供了更多的控制和灵活性,特别适用于更复杂的多线程场景。而synchronized由于其简单性,更适用于那些不需要高级功能和低至中等线程竞争的场景。选择哪一个取决于具体需求和使用场景。

想要线程停止有哪些方式?
在Java中,安全地停止线程是多线程编程中的一个常见需求。过去,Java提供了stop()方法来停止线程,但由于这种方法会导致线程立即停止,可能导致共享资源处于不一致状态或其他线程在等待锁时发生死锁,因此这个方法已被废弃。现在,有几种更安全和优雅的方法来停止一个线程:

1. 使用中断

  • 调用线程的interrupt()方法
    • 在线程中断点(如sleep()wait()join()等)会抛出InterruptedException,可以捕获这个异常并优雅地结束线程。
    • 线程可以通过检查中断标志(使用Thread.interrupted()Thread.currentThread().isInterrupted())来响应中断。

2. 使用标志

  • 设置自定义标志
    • 在线程的运行方法中,使用一个自定义的布尔标志来控制循环或运行状态。
    • 当需要停止线程时,外部代码可以设置这个标志为false

3. 使用Future.cancel()(对于ExecutorService

  • 如果线程是通过ExecutorService提交的,可以使用Future对象来请求取消。
  • 调用Future.cancel(true)将尝试取消任务的执行。如果任务已经开始,它将尝试中断线程。

4. 使用volatile变量

  • 使用volatile关键字声明的变量确保所有线程都能看到变量的最新值。
  • 可以使用一个volatile boolean变量作为一个信号,告诉线程何时停止。

代码示例

使用中断
public class MyThread extends Thread {public void run() {while (!Thread.interrupted()) {// 执行任务}// 清理资源并停止执行}
}MyThread thread = new MyThread();
thread.start();
// 一段时间后
thread.interrupt();
使用自定义标志
public class MyThread extends Thread {private volatile boolean running = true;public void run() {while (running) {// 执行任务}// 清理资源并停止执行}public void stopRunning() {running = false;}
}MyThread thread = new MyThread();
thread.start();
// 一段时间后
thread.stopRunning();

注意事项

  • 不要使用Thread.stop()方法停止线程,因为它是不安全的。
  • 始终确保线程的停止操作是安全的,不会导致资源泄露或状态不一致。

总之,正确停止线程的关键在于提供一种机制,使线程可以在完成当前工作后安全地终止,而不是强行从外部中断其执行。

哪些方式会造成线程死锁?
在Java中,线程死锁通常发生在两个或多个线程永久性地阻塞对方,等待对方释放锁,从而无法继续执行。造成死锁的主要原因通常涉及一组互相竞争资源的线程,这些线程彼此之间因为锁的竞争而无法前进。以下是一些可能导致线程死锁的常见情况:

1. 锁顺序死锁

当两个或多个线程以不同的顺序获取相同的锁时,可能会发生死锁。例如,线程A持有锁L1并试图获取锁L2,同时线程B持有锁L2并试图获取锁L1。

2. 循环等待

当两个或多个线程形成一个循环等待链时,每个线程都在等待链中的下一个线程释放锁。这是造成死锁的一个典型模式。

3. 资源死锁

线程对多个资源的需求可能导致死锁。例如,线程A等待线程B持有的资源,而线程B等待线程A持有的资源。

4. 嵌套锁

当一个线程在持有一个锁的同时尝试获取另一个锁时,如果其他线程以相反的顺序尝试获取这些锁,就可能产生死锁。

5. 不可中断的操作

线程可能在等待一个不可中断的资源(例如I/O操作)时阻塞,如果其他线程需要等待这个阻塞线程释放的资源,也可能导致死锁。

代码示例

public class DeadlockDemo {private static final Object Lock1 = new Object();private static final Object Lock2 = new Object();public static void main(String args[]) {ThreadDemo1 T1 = new ThreadDemo1();ThreadDemo2 T2 = new ThreadDemo2();T1.start();T2.start();}private static class ThreadDemo1 extends Thread {public void run() {synchronized (Lock1) {System.out.println("Thread 1: Holding lock 1...");try { Thread.sleep(10); }catch (InterruptedException e) {}System.out.println("Thread 1: Waiting for lock 2...");synchronized (Lock2) {System.out.println("Thread 1: Holding lock 1 & 2...");}}}}private static class ThreadDemo2 extends Thread {public void run() {synchronized (Lock2) {System.out.println("Thread 2: Holding lock 2...");try { Thread.sleep(10); }catch (InterruptedException e) {}System.out.println("Thread 2: Waiting for lock 1...");synchronized (Lock1) {System.out.println("Thread 2: Holding lock 1 & 2...");}}}}
}

在这个示例中,ThreadDemo1ThreadDemo2 分别尝试以不同的顺序获取 Lock1Lock2,这可能导致死锁。

避免死锁的策略

  • 锁顺序:确保所有线程以相同的顺序获取锁。
  • 锁超时:使用带有超时的锁获取机制,如tryLock()
  • 死锁检测:在系统设计中实现死锁检测机制,并相应地采取措施。
  • 减少锁的使用:尽可能减少同步块的使用,避免不必要的锁。
  • 使用并发工具类:利用Java的java.util.concurrent包中的并发工具类,如ReentrantLock,它们提供了更灵活的锁定机制。

sleep,wait,yield,join的区别?

在Java中,sleep(), wait(), yield(), 和 join() 是用于控制线程行为的重要方法,它们在多线程编程中有着各自的作用和特性。理解它们之间的区别对于编写有效的多线程代码非常重要。

1. sleep()

  • 所属类Thread
  • 目的:使当前执行的线程暂停执行指定的时间(给定的毫秒数),不释放任何锁。
  • 使用场景:暂停线程执行一段时间,不涉及锁资源的释放或等待。

2. wait()

  • 所属类Object
  • 目的:使当前线程进入等待状态直到另一个线程调用相同对象的notify()notifyAll()方法。在调用wait()时,线程必须持有该对象的锁,调用后会释放这个对象的锁。
  • 使用场景:线程需要等待特定条件的满足,并在等待期间释放对象锁以允许其他线程修改这个条件。

3. yield()

  • 所属类Thread
  • 目的:使当前线程让出CPU执行时间,但不释放任何锁资源。yield()的调用不会导致线程状态的改变,它只是建议线程调度器当前线程愿意放弃当前的CPU资源,但线程调度器可以自由忽略这个提示。
  • 使用场景:当一个线程认为自己不那么重要,或者希望给予其他相同优先级的线程执行机会时。

4. join()

  • 所属类Thread
  • 目的:等待调用join()方法的线程结束。换句话说,假设在线程A中调用了线程B的join()方法,线程A将会被挂起,直到线程B完成执行后才会继续执行。
  • 使用场景:当一个线程需要等待另一个线程完成工作之后再继续执行。

比较

  • 锁的释放

    • wait()方法在等待时会释放锁,而sleep()yield()不会释放任何锁。
    • join()方法不涉及锁的概念,但它会使调用者等待直到目标线程完成。
  • 控制精度

    • sleep()可以精确地控制需要暂停的时间。
    • wait()通常用于线程间的交互和条件等待,依赖于外部因素来唤醒。
    • yield()对于线程调度的影响不确定,取决于具体的线程调度器的实现。
    • join()用于等待另一个线程完成,其等待时间取决于目标线程的执行时间。
  • 异常处理

    • sleep(), wait(), 和 join() 都会抛出InterruptedException,这表明线程的等待、睡眠或占用状态被中断了。
    • yield()不会抛出InterruptedException

理解这些方法的不同之处有助于更好地利用Java的多线程机制,并编写出更有效、更稳定的并发应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/174262.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库第十第十一章 恢复和并发简答题

数据库第一章 概论简答题 数据库第二章 关系数据库简答题 数据库第三章 SQL简答题 数据库第四第五章 安全性和完整性简答题 数据库第七章 数据库设计简答题 数据库第九章 查询处理和优化简答题 1.什么是数据库中的事务?它有哪些特性?这些特性的含义是什么…

Vue的八个基础命令及作用

1.v-text 作用:获取data数据, 设置标签的内容,以纯文本进行显示v-text 会覆盖 标签中的内容,如果想要拼接数据,可以直接在v-text中拼接如果拼接的是数字:直接使用 “”如果拼接的是字符串,需要使用与外部不同的引号进…

函数指针数组指针数组传参的本质字符指针

🚀 作者:阿辉不一般 🚀 你说呢:不服输的你,他们拿什么赢 🚀 专栏:爱上C语言 🚀作图工具:draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话,还请点赞…

XSTRING与STRING之间的互转,base64,长文本,科学计数法

XSTRING的介绍 SAP ABAP 理解RAWSTRING(XSTRING) 类型-腾讯云开发者社区-腾讯云 XString,String以及SString 类型区别 | 摆渡SAP SAP ABAP 理解RAWSTRING(XSTRING) 类型 RAWSTRING 和 STRING 类型具有可变长度。可以指定这些类型的最大长度,但没有上限。 SSTRI…

代码浅析DLIO(二)---预积分与单点去畸变

0. 简介 我们刚刚了解过DLIO的整个流程,我们发现相比于Point-LIO而言,这个方法更适合我们去学习理解,同时官方给出的结果来看DLIO的结果明显好于现在的主流方法,当然指的一提的是,这个DLIO是必须需要六轴IMU的&#x…

【ZYNQ】SD 卡读写及文件扫描实验

SD 卡控制器(SD/SDIO Controller) ZYNQ 中的 SD 卡控制器符合 SD2.0 协议规范,接口兼容 eMMC、MMC3.31、SDIO2.0、SD2.0、SPI,支持 SDHC、SDHS 器件。SD 卡控制器支持 SDMA(单操作 DMA)、ADMA1&#xff08…

数据结构-顺序表

文章目录 线性表概念顺序表静态顺序表动态顺序表 总结 线性表概念 线性表是最基本、最简单、也是最常用的一种数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…线性表(linear> list)是数据结构的一种,一个线性表是n个具…

2024年福建省职业院校技能大赛高职组“软件测试”赛项样题

2024年福建省职业院校技能大赛 高职组“软件测试”赛项样题 任务一:功能测试(45分) 1、测试计划(5分) (1)任务描述 针对功能测试任务,划分和界定测试范围,分解测试任…

蚂蚁庄园小课堂答题今日答案最新

蚂蚁庄园小课堂答题今日答案最新 温馨提醒:由于本文章会停留在一个固定的更新时间上,包含当前日期最新的支付宝蚂蚁庄园小课堂答题今日答案。如果您看到这篇文章已成为过去时,请按下面的方法进入查看天天保持更新的最新今日答案; …

Linux 网络通信

(一)套接字Socket概念 Socket 中文意思是“插座”,在 Linux 环境下,用于表示进程 x 间网络通信的特殊文件 类型。本质为内核借助缓冲区形成的伪文件。 既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。Linux 系统…

Windows11安装后跳过联网登录

Windows11安装后跳过联网登录 实验设备: VMware17Pro虚拟机中使用Windows11镜像安装Windows11操作系统,并且在虚拟机中测试跳过联网登录。 步骤 说明:物理卸载网卡(在虚拟机上禁用网卡)没用 思路: sh…

8.统一异常处理 + 统一记录日志

目录 1.统一异常处理 2.统一记录日志 1.统一异常处理 在 HomeController 类中添加请求方法(服务器发生异常之后需要统一处理异常,记录日志,然后转到 500 页面,需要人工处理重定向到 500 页面,提前把 500 页面请求访问…

经典神经网络——AlexNet模型论文详解及代码复现

一、背景 AlexNet是在2012年由Alex Krizhevsky等人提出的,该网络在2012年的ImageNet大赛上夺得了冠军,并且错误率比第二名高了很多。Alexnet共有8层结构,前5层为卷积层,后三层为全连接层。 论文地址:ImageNet Classif…

ModuleNotFoundError: No module named ‘mdtex2html‘ module已经安装还是报错,怎么办?

用streamlit运行ChatGLM/basic_model/web_demo.py的时候,出现了module not found: ModuleNotFoundError: No module named mdtex2html Traceback: File "/home/haiyue/.local/lib/python3.10/site-packages/streamlit/runtime/scriptrunner/script…

【阿里云】图像识别 智能分类识别 增加网络控制功能点(三)

一、增加网络控制功能 实现需求TCP 心跳机制解决Soket异常断开问题 二、Linux内核提供了通过sysctl命令查看和配置TCP KeepAlive参数的方法。 查看当前系统的TCP KeepAlive参数修改TCP KeepAlive参数 三、C语言实现TCP KeepAlive功能 四、setsockopt用于设置套接字选项的系…

leetcode做题笔记907. 子数组的最小值之和

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。 由于答案可能很大,因此 返回答案模 10^9 7 。 示例 1: 输入:arr [3,1,2,4] 输出:17 解释&…

Qt4利用MVC开发曲线数据编辑器

目录 1 需求 2 开发流程 1 搭建框架 2 构造函数 3 打开工程 4 实现应用程序参数加载 5 QCustomPlot和TableView的联动 6 数据的可视化修改 7 列表点击事件事先键盘控制 8 表格实现复制,粘贴,删除等一系列功能 9 曲线实现自适应范围和统一范围…

【JMeter】运行方式

第一种: 使用GUI 操作: 在JMeter界面菜单导航上点击运行按钮 一般用作创建TestPlan和调试脚本增加java堆空间来满足测试环境 第二种:使用CLI(Command Line) 性能测试一般请求量比较大,为了节省资源 CLI参数用法: 字段…

零代码,无限可能:打造无服务器应用程序的成功秘诀!

在应用程序构建时,代码作为一组打包成应用程序的计算机指令,仅在有计算机(服务器)与之交互时才会发挥作用。对于无服务器化的应用程序,它并不是看似无需任何硬件即可运行的应用程序。无服务器是一种基于功能的架构&…

C语言-方阵循环右移

本题要求编写程序,将给定nn方阵中的每个元素循环向右移m个位置,即将第0、1、⋯、n−1列变换为第n−m、n−m1、⋯、n−1、0、1、⋯、n−m−1列。 输入格式: 输入第一行给出两个正整数m和n(1≤n≤6)。接下来一共n行&am…