关于Java多线程的一些随笔
Synchronized与ReentrantLock有哪些相同点和不同点?
在Java中,synchronized关键字和ReentrantLock类都用于管理线程间的同步,但它们在实现方式、功能和灵活性方面存在一些差异。以下是它们的相同点和不同点:
相同点
-
互斥性:
synchronized和ReentrantLock都提供了线程互斥的机制,确保在同一时间只有一个线程可以执行特定代码段。 -
防止线程干扰:它们都用于解决线程安全问题,避免多线程环境下的数据不一致性和竞争条件。
-
可重入性:这两种机制都是可重入的,即同一个线程可以多次获取已经持有的锁。
-
锁定代码块或对象:它们都可以锁定代码块或整个方法,以保护关键部分的代码不被多线程同时执行。
不同点
-
实现方式:
synchronized是Java的内置关键字,其实现是隐藏的,用户无需手动管理锁的获取和释放。ReentrantLock是Java标准库中的API,需要显式地创建锁对象,显式地获取和释放锁。
-
功能特性:
ReentrantLock提供了比synchronized更多的功能,如可中断的锁获取、尝试非阻塞地获取锁(tryLock())、设置公平锁等。synchronized不支持这些高级特性。
-
条件变量:
ReentrantLock与Condition对象配合,可以分别控制线程的等待和唤醒,这为线程间通信提供了更多的灵活性。synchronized则是配合Object类的wait()、notify()和notifyAll()方法来实现线程间的通信。
-
锁的公平性:
ReentrantLock允许用户选择是使用公平锁还是非公平锁。synchronized不保证公平性,没有提供公平锁的选项。
-
性能和优化:
- 在Java 6及以后版本中,
synchronized的性能得到了显著提升,尤其在低至中等线程竞争的情况下。 ReentrantLock可能在高竞争环境下表现更优,特别是在使用公平锁或者需要更复杂的条件同步时。
- 在Java 6及以后版本中,
-
锁的可中断性:
ReentrantLock允许在等待锁的过程中响应中断。synchronized块内的线程等待获得锁时不能被中断。
总结
虽然synchronized和ReentrantLock都用于实现线程同步,但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...");}}}}
}
在这个示例中,ThreadDemo1 和 ThreadDemo2 分别尝试以不同的顺序获取 Lock1 和 Lock2,这可能导致死锁。
避免死锁的策略
- 锁顺序:确保所有线程以相同的顺序获取锁。
- 锁超时:使用带有超时的锁获取机制,如
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的多线程机制,并编写出更有效、更稳定的并发应用程序。
相关文章:
关于Java多线程的一些随笔
Synchronized与ReentrantLock有哪些相同点和不同点? 在Java中,synchronized关键字和ReentrantLock类都用于管理线程间的同步,但它们在实现方式、功能和灵活性方面存在一些差异。以下是它们的相同点和不同点: 相同点 互斥性&…...
Answering difficult questions in other way
I’m not (too) sure Q:Do you think computers make life easier? A:I’m not (too) sure, to be honest, but I reckon they do make life easier because… I can’t say for sure, but … Q:Do you think computers make lif…...
RabbitMQ教程:Linux下安装、基本命令与Spring Boot集成
RabbitMQ教程:Linux下安装、基本命令与Spring Boot集成 1. RabbitMQ简介 RabbitMQ是一个开源的消息代理和队列服务器,用于通过轻量级消息传递协议(AMQP)在分布式系统中传递消息。它支持多种编程语言,包括Java、Pytho…...
王者荣耀小游戏
第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt; package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.…...
JAVA小游戏“简易版王者荣耀”
第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; im…...
Nginx高级
Nginx高级 第一部分:扩容 通过扩容提升整体吞吐量 1.单机垂直扩容:硬件资源增加 云服务资源增加 整机:IBM、浪潮、DELL、HP等 CPU/主板:更新到主流 网卡:10G/40G网卡 磁盘:SAS(SCSI) HDD(机械…...
深度学习中小知识点系列(三) 解读Mosaic 数据增强
前言 Mosaic数据增强,这种数据增强方式简单来说就是把4张图片,通过随机缩放、随机裁减、随机排布的方式进行拼接。Mosaic有如下优点: (1)丰富数据集:随机使用4张图片,随机缩放,再随…...
telnet-MISC-bugku-解题步骤
——CTF解题专栏—— 题目信息: 题目:这是一张单纯的图片 作者:未知 提示:无 解题附件: 解题思路: (⊙﹏⊙)这是个什么文件pcap文件分析_pcap文件打开-CSDN博客查了一下,但没看懂,…...
大数据Doris(二十九):数据导入(Insert Into)
文章目录 数据导入(Insert Into) 一、创建导入...
jmeter测试dubbo接口
本文讲解jmeter测试dubbo接口的实现方式,文章以一个dubbo的接口为例子进行讲解,该dubbo接口实现的功能为: 一:首先我们看服务端代码 代码架构为: 1:新建一个maven工程,pom文件为: 1…...
分类预测 | Matlab实现基于DBN-SVM深度置信网络-支持向量机的数据分类预测
分类预测 | Matlab实现基于DBN-SVM深度置信网络-支持向量机的数据分类预测 目录 分类预测 | Matlab实现基于DBN-SVM深度置信网络-支持向量机的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.利用DBN进行特征提取,将提取后的特征放入SVM进行分类…...
android系统新特性——用户界面以及系统界面改进
用户界面改进 Android用户界面改进最明显的就是MD了。MD是Google于2014年推出的设计语言,它是一套完整的设计系统,包含了动画、样式、布局、组件等一系列与设计有关的元素。通过对这些行为的描述,让开发者设计出更符合目标的软件,…...
电量计驱动代码
外部电量计驱动代码,直接上代码了,懒,不做细节分析。。。。。 /** Fuelgauge battery driver** This package is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Soft…...
如何将音频添加到视频并替换视频中的音轨
随着视频流媒体网站的流行和便携式设备的发展,你可能越来越倾向于自己制作视频并在互联网上分享。有时,你可能还需要编辑视频并为其添加背景音乐,因为音乐总是对视频的感知起着神奇的作用。 那如何给视频添加音频呢?或者如何用新…...
Android 单元测试初体验
Android 单元测试初体验 前言一、单元测试是什么?二、简单使用1.依赖2.单元测试代码简单模版及解释 总结 前言 当初在学校学安卓的时候,老师敢教学进度,翻到单元测试这一章节的时候提了两句,没有把单元测试当重点讲,只…...
HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙应用开发】
文章目录 ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化@Observed 类装饰器说明装饰器参数类装饰器的使用@ObjectLink 变量装饰器说明装饰器参数同步类型允许装饰的变量类型被装饰变量的初始值举例装饰器的限制条件观察变化和行为表现观察的变化框架行为使用场景1.…...
设计问卷调查问题的技巧二:确定问题的结构与顺序
上篇文章中,我们了解到设计问卷调查问卷的技巧有保持问题中立、少用开放式问题、保持全名平衡的答案集、谨慎设置单一回答。在这篇文章中,我们将继续深入探讨设计问卷调查问题的剩余5大技巧! Tip5:注意问题的顺序 虽然您可以任意…...
kubernetes使用nfs创建pvc部署mysql stateful的方法
kubernetes创建的pod默认都是无状态的,换句话说删除以后不会保留任何数据。 所以对于mysql这种有状态的应用,必须使用持久化存储作为支撑,才能部署成有状态的stateful. 最简单的方法就是使用nfs作为网络存储,因为nfs存储很容易被…...
JavaScript WebApi(二) 详解
监听事件 介绍 事件监听是一种用于在特定条件下执行代码的编程技术。在Web开发中,事件监听器可以用于捕获和响应用户与页面交互的各种操作,如点击、滚动、输入等。 事件监听的基本原理是,通过在特定元素上注册事件监听器,当事件…...
纯新手发布鸿蒙的第一个java应用
第一个java开发鸿蒙应用 1.下载和安装华为自己的app开发软件DevEco Studio HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 2.打开IDE新建工程(当前用的IDEA 3.1.1 Release) 选择第一个,其他的默认只能用(API9)版本,…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
五、jmeter脚本参数化
目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...
欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!
多连接 BLE 怎么设计服务不会乱?分层思维来救场! 作者按: 你是不是也遇到过 BLE 多连接时,调试现场像网吧“掉线风暴”? 温度传感器连上了,心率带丢了;一边 OTA 更新,一边通知卡壳。…...
