【Java基础之线程同步(二)】java线程同步:synchronized关键字,Lock接口以及可重入锁ReentrantLock

Java多线程的同步:synchronized关键字、Lock接口、volatile关键字 Java 多线程同步是解决资源共享冲突的核心机制,主要通过协调线程对共享资源的访问顺序与权限,避免数据不一致和竞态条件。在多线程的环境中,经常会碰到数据的共享问题,即当多线程需要访问同一个资源时,它们需要以某种顺序来确保该资源在某一时刻只能被一个线程使用,否则,程序的运行结果将会是不可预料的,在这种情况下就必须对数据进行同步。例如多个线程同时对同一数据进行写操作。 阅读详情

多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修改,就会导致修改的状态不一致.

用一个实际的例子来说明线程同步的必要性:

package cn.outofmemory.locks;

public class LockDemo implements Runnable {
	private int counter = 0;
	
	public void run() {
		int loopTimes = 10000;
		while (loopTimes > 0) {
		  counter ++;				
			loopTimes --;
		}
	}

	public static void main(String[] args) throws InterruptedException {
		LockDemo demo = new LockDemo();
		
		Thread[] threads = new Thread[]{
				new Thread(demo), new Thread(demo),new Thread(demo), new Thread(demo),new Thread(demo)
		};
		
		
		for (Thread t : threads) {
			t.start();
		}
		
		for (Thread t : threads) {
			t.join();
		}
		
		System.out.println("demo's counter is " + demo.counter);
	}
}

这段代码中的LockDemo类实现了Runnable接口,在run方法中对其私有变量counter递加了10000次。在main方法中我们首先初始化了一个LockDemo对象,然后初始化了5个线程,这5个线程公用一个LockDemo的实例。 
然后我们一次启动这5个线程,然后通过join等待所有线程结束,最后输出demo实例的counter值来。 

运行程序,我这儿得到这样一个输出结果:

demo's counter is 44041

本来5个线程每个线程递加10000次,应该得到的结果是50000,而实际的结果是44041. 

如果你也运行此程序有可能会得到不一样的结果。这取决于这5个线程造成了多少次的冲突。从我的输出结果看,这段程序的5个线程造成了大约6000次的内存争用冲突。 
在实际应用中,这是不可用的。

改进程序,避免冲突

我们可以分析一下,这5个线程的冲突出现在什么地方,他们公用了demo对象,同时对demo对象的成员变量counter做递加,也就是说冲突出现在对counter递加这一步上。 
我们在这一步操作上加上synchronzied关键字,让5个线程执行到对counter++这步代码时单独运行,应该就可以解决问题了。 

修改后的run方法代码:

	public void run() {
		int loopTimes = 10000;
		while (loopTimes > 0) {
			synchronized (this) {
				counter ++;				
			}
			loopTimes --;
		}
	}

我们再次运行程序会得到如下确定的输出结果:

demo's counter is 50000

这次得到的结果是符合我们的预期的,我们通过synchronized关键字解决了问题。

synchronized关键字是jvm虚拟机的关键字,在java.util.concurrent.locks命名空间中还有一个Lock接口,和Lock接口的实现类ReentrantLock(可重入锁)。 ReentrantLock可以实现和synchronized关键字相同的功能,而且更为灵活,在极端的情况下性能会更好一些。

我们看下使用可重入锁ReentrantLock解决线程同步的方法:

	private final Lock lock = new ReentrantLock();
	
	public void run() {
		int loopTimes = 10000;
		while (loopTimes > 0) {
			try {
				lock.lock();
				counter ++;				
			} finally {
				lock.unlock();
			}
			loopTimes --;
		}
	}


我们在LockDemo中添加了一个final的成员变量lock,它是一个ReentrantLock的实例。 在run方法中,在counter++这行代码两边加上了try .. finally ..语句, 
当线程执行到try块之后,首先通过lock.lock()获得锁,获得锁之后再执行counter++,最后在finally语句块中通过lock的unlock方法释放锁。 

我们可以运行修改后的代码,输出如下:

demo's counter is 50000

输出结果符合逻辑预期。

synchronized获得的内部锁存在一定的局限

1. 不能中断一个正在试图获得锁的线程 

2. 试图获得锁时不能像trylock那样设定超时时间 

3. 每个锁只有单一的条件,不像condition那样可以设置多个

synchronzied关键字和可重入锁ReentrantLock选择的最佳实践:

1. 如果synchronized关键字适合程序,尽量使用它,可以减少代码出错的几率和代码数量 
2. 如果特别需要Lock/Condition结构提供的独有特性时,才使用他们 
3. 许多情况下可以使用java.util.concurrent包中的一种机制,它会为你处理所有的加锁情况

多线程——Lock锁与synchronized锁 Lock锁 悲观锁 接口java.util.concurrent.locks.Lock 接口java.util.concurrent.locks.ReentrantLock 实现类 可重入锁 非公平锁public void lock() 加同步锁public void unlock() 释放同步锁。 阅读详情

相关推荐

【多线程】可重入锁 Reentrant Lock

可重入锁是一种允许同一线程多次获取同一把锁的同步机制,避免了自死锁问题。文章通过房间门锁的比喻,解释了可重入锁的核心概念:记录持有线程和重入次数。分析了非可重入锁在递归调用和方法互调时会导致死锁的问题,并展示了Java中两种可重入锁实现方式 - synchronized关键字和ReentrantLock类。可重入锁通过维护持有线程和计数器,使同一线程可以安全地多次获取锁,是面向对象编程中处理复杂调用关系的必备同步工具。

guigenyi的专栏 994

synchronized原理

摘要:Java中的synchronized关键字是实现线程同步的重要机制,具有以下特性:1)作为隐式可重入锁,支持锁升级(偏向锁→轻量级锁→重量级锁);2)保证原子性、可见性和有序性;3)使用方法包括方法加锁和同步代码块。底层原理通过monitor对象实现,JDK1.6后优化了锁机制,引入偏向锁、轻量级锁和自适应自旋锁等策略提升性能。此外,JVM会进行锁粗化和锁消除优化。该机制适用于解决多线程并发问题,但需根据具体场景选择合适的同步策略。

纯洁的小魔鬼 5837

深入解析数据通信中的码元速率与比特率:从基础到实战应用

本文深入解析了数据通信中的核心概念码元速率与比特率,通过生动的比喻和公式(比特率=波特率×log₂(M))揭示其本质关系。文章结合BPSK、QPSK、16QAM等调制技术,剖析了从4G/5G到LoRa等实战场景中如何权衡速率、距离与可靠性,并提供了软考真题解析与系统设计建议,帮助读者从理论到应用全面掌握数据速率优化。

weixin_29324877的博客 213

Synchonrized介绍

目录 前提知识 Synchronized介绍 Synchronized使用场景 synchronized底层原理 Synchronized的可重入的实现机制 Monitor监视器锁 什么是monitor 对象布局 Synchronized的8锁现象 前提知识 多线程编程中,有可能会出现多个线程同时访问同一个共享变量,可变资源的情况,这个资源我们称之为临界资源;这种资源对象可能是:对象,变量,文件等. 共享:资源可以由多个线程同时访问 可变:资源可以在其生命周期内被修改 引出的问题:

qq_44447372的博客 717

PacketTacer烟雾传感器读数为0的解决方法

PacketTacer烟雾传感器读数为0的解决方法

ChloeMax_的博客 1903

RK3568(buildroot)利用squashfs+overlay实现嵌入式系统高可靠存储方案

本文详细介绍了在RK3568嵌入式平台上,基于Buildroot系统,利用squashfs只读根文件系统与overlayfs可写层相结合的高可靠存储方案。该方案能有效防止设备意外断电导致的系统文件损坏,通过内核配置、启动脚本编写及镜像制作,实现系统核心的只读保护与用户数据的持久化分离,显著提升嵌入式设备的现场稳定性。

weixin_29189381的博客 547

Java线程(Lock接口,重入锁,读写锁)

本文旨在介绍Java中的读写锁和重入锁,含有相关代码做参考使用

m0_57532232的博客 184

PX4代码解析(1)

前言 做pixhawk飞控有一段时间了,但在学习过程中遇到许多困难,目前网上找不到比较完整的PX4学习笔记,我打算结合自己理解,写写自己对PX4源码的理解,不一定对,只是希望与各位大佬交流交流,同时梳理一下无人机知识。 目前打算分享以下几个内容:代码架构;通信协议;姿态解算算法,控制算法。先这样,后面想到再加。本章先来聊聊px4代码结构 一、代码整体结构 既然要聊px4代码结构,那就先把px4代码结构图放出来,因为px4源码仍然在不断更新迭代,因此老版本与新版本目录结构可能有些不同,我的代码解析参考版本为V

qq_36903625的博客 1万+

Java中Synchronized的用法

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 3.修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 4..

阳光日志 51万+

大模型在心律失常预测及治疗方案制定中的应用研究报告

目录一、引言1.1 研究背景与意义1.2 研究目的与方法1.3 研究创新点二、大模型技术概述2.1 大模型基本原理2.2 常见大模型类型及特点2.3 大模型在医疗领域的应用现状三、心律失常的术前预测与准备3.1 术前心律失常预测的重要性3.2 大模型在术前预测中的应用案例3.3 基于预测结果的术前准备方案四、术中监测与实时调整4.1 术中监测心律失常的方法与技术4.2 大模型辅助术中决策的机制4.3 实时调整手术方案的策略与实践五、术后恢复与并发症风险预测5.1 术后心律失常的监测与评估5.2 大模型预测术

嵌入式毕设/课设资料清单(速查手册·文档模板·题库,持续更新)→ 见最新文章 1596

普通用户也能免费使用 SAP Joule!

点击 SAP Joule 给出的按钮之后,SAP Business Application Studio 左侧显示的界面,就从 SAP Joule 替换成了 SAP Fiori tools 的 Project Accelerator 工具。接下来就是在后者中标准的操作流程了。笔者之前的文章,有朋友提问,既然 ChatGPT,DeepSeek,Grok 这些主流 AI 工具,回答 SAP 相关问题时都经常翻车,那 SAP 自家的 Joule 表现又如何呢?还有朋友评论:如何才能使用 SAP Joule?

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1018

分析java中的接口【重中之重】

重要的java接口 文章目录重要的java接口1.接口的理解2.接口的语法3.接口和抽象类的区别4.实现类的注意5.接口的意义 1.接口的理解 接口在java中担任着重要的职责,是java的一大技术要点,简单的说:接口就是一种标准,是接口的实现者和接口的使用者都必须遵守的一个约定; 接口和类在Java中不在同一个分类框,所以虽然可以将接口理解为一种特殊的抽象类,但是他们之间还是大有不同的 前面的...

sen123324的博客 259

Python爬虫实战:中国土地市场网招拍挂数据抓取与分析

本文详细介绍了如何使用Python爬虫技术从中国土地市场网抓取土地招拍挂数据,并进行初步的数据分析与可视化。文章涵盖了爬虫的基本原理、反爬虫策略应对、数据清洗与存储、数据分析与可视化等多个方面,为土地市场研究者提供了一套完整的数据获取与分析解决方案。

2201_76125261的博客 684

线程安全(二)Lock 什么是Lock线程锁?与synchronized区别在哪?Lock锁是如何实现等待通知的?如何实现线程顺序执行?

一.synchronized的缺陷 二.Lock接口的特性 三.Lock接口基本的方法: 四、Lock接口的实现类:ReentrantLock 五、ReadWriteLock 六、Condition接口 简介 Condition接口的常见方法: . 使用单个Condition实例实现等待/通知机制: 使用多个Condition实例实现等待/通知机制: 使用Condition实现顺序执行 七、ReentrantReadWriteLock 八、公平锁与非公平锁 九、可重入锁

T_Antry 2万+

Keras神经网络可视化模块keras.utils.visualize_util的安装配置方法

本文介绍了如何安装和配置keras.utils.visualize_util模块,并提供了一个简单的示例演示如何使用该模块来可视化神经网络的结构。在上述代码中,我们首先定义了一个简单的神经网络模型,该模型具有一个输入层、一个隐藏层和一个输出层,其中隐藏层具有512个神经元,输出层具有10个神经元。运行上述代码后,我们将在当前工作目录下找到一个名为model.png的文件,它显示了神经网络的结构图。这种方式有效地展示了整个过程,让我们能够更好地理解神经网络的结构,方便对其进行改进和调试。

. 892

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

java中同步锁synchronized与Lock的区别

同步锁: java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。 java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B...

gm371200587的博客 3万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java线程同步中的Lock锁,什么是ReentrantLock锁,ReentrantLock锁如何使用(一)

java、JUC

zhangfuping123456789的博客 7581

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Lock锁 Synchronized关键字 ReentrantLock

锁降级:在同一个线程里,获取写锁后可以再获取读锁,释放写锁后就持有了读锁,这种现象称为锁降级,这可以保证线程能读到最新修改的数据,其他线程读锁也能获取到这次更新,阻塞其他写操作来保证只读到当前写完的数据。Lock锁的实现ReentrantLock也是可重入锁,使用显式锁时,要注意释放锁和获取锁的次数保持一致,防止死锁。(如果频繁写入,可能出现读操作一直自旋的情况,效率降低)的情况下,可以显著提示并发性能,并且可以在乐观读途中获取到写锁,对数据进行更新,可以解决读写锁的写锁饥饿问题。

deku_的博客 854

轻松掌握Java多线程 - 第八章:Lock接口与ReentrantLock

摘要:本文介绍了Java中Lock接口与ReentrantLock作为synchronized关键字的替代方案。通过代码示例对比了两者的差异,展示了Lock接口在可中断性、超时机制、非阻塞获取等方面的优势。文章详细讲解了ReentrantLock的基本使用方法,包括可中断锁、超时锁等特性,并分析了公平锁与非公平锁的选择策略。最后总结了Lock接口的最佳实践,为开发者处理复杂并发场景提供了更灵活的解决方案。

qianmoQ - 关注云计算,关注大数据 1700

Synchronized Lock 锁 同步

如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系。 字符串作为锁对象的参考 一、synchronized的性质 1、可重入性 官方解释:指的是同一线程的外层函数获得锁之后,内层函数可以直接再次获得该锁; 通俗解释:获得一次锁之后,如果调用其它同步方法,不需要重新获取锁,可以直接使用; 在方法1中调用方法2,两个方法都是同步方法,在获取方法1的锁之后,是可以直接调用方法2,而不需要重新获取锁,这就是可重入性,可重入性是线程范围,可以...

qq_30436011的博客 3587

彻底理解Java并发:ReentrantLock锁

本篇内容包括:为什么使用 Lock、Lock 锁注意事项、ReentrantLock 和 synchronized 对比、ReentrantLock (加锁、解锁、公平锁与非公平锁、ReentrantLock 如何实现可重入)等内容。

栗筝i的博客 6033

synchronized 和Lock区别以及可重入锁(ReentrantLock)

对于synchronized 还没理解的可以先看看我之前写的这篇博客讲解synchronized 先对synchronized有一个初步了解:https://blog.youkuaiyun.com/dekulugu/article/details/108929818 一、synchronized 和Lock区别 知道了synchronized 和Lock,他们都是实现了多线程的加锁,那么我们就要明白什么时候适合什么锁。 区别如下: Lock是java的一个interface接口,而synchronized是Java

dekulugu的博客 1495

深入浅出ReentrantLock(可重入锁)

一、前言 在Java 5.0之前,在协调对共享对象的访问的时可以使用的机制只有synchronized 和 volatile。Java 5.0 增加了一种新的机制:ReentrantLock 。与之前提到过的机制相反,ReentrantLock 并不是一种替代内置加锁的方法,而是当内置解锁机制不适用时,作为一种可选择的高级功能。 二、简介 ReentrantLock 重入锁实现了 Lock和 ...

牧小农 3759

Java——多线程高并发系列之Lock、ReentrantLock

Java——多线程高并发系列之Lock、ReentrantLock

贝尔摩德苦艾酒 7738

synchronized/Lock锁详解

synchronized和Lock锁如何使用,demo笔记,一文搞懂!

但行好事,莫问前程 1734

Java 多线程同步机制深度解析:从 synchronized 到 Lock

本文全面解析了Java中的synchronized和Lock两种线程同步机制。首先分析了多线程并发问题的根源,然后深入讲解synchronized的实现原理、锁升级过程及使用方法(同步代码块/方法)。接着介绍Lock接口及其实现ReentrantLock的高级特性(可中断锁、公平锁等)。通过对比分析二者的优缺点,给出了同步机制的最佳实践建议:简单场景优先使用synchronized,复杂场景选择Lock,并强调最小化同步范围和确保锁释放的重要性。

qq_40303030的博客 1055
上一篇: 【Java基础之Object类(二)、线程同步(一)】Java中使用Object类的wait,notify,notifyAll做线程调度
下一篇: 【Java基础之线程同步(三)】使用ReentrantLock Condition实现线程同步
cangchen
博客等级 码龄18年 108粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值