探索Java并发编程

news/2024/5/21 5:34:41

### 探索Java并发编程:深入理解synchronized关键字

在Java并发编程领域,确保线程安全是一项至关重要的任务。`synchronized`关键字作为Java提供的原生同步机制,扮演着保护共享资源免受并发访问影响的重要角色。本篇博客将深入解析`synchronized`的工作原理、使用方式以及其在多线程环境下的应用策略,助您在编写并发程序时游刃有余。

#### 1. synchronized基础

`synchronized`可以应用于方法或代码块,以实现对特定资源的互斥访问控制。它的核心作用是保证同一时刻只有一个线程能够执行特定的代码段,从而避免了数据的不一致性问题。

- **方法级同步**:直接在方法声明上使用`synchronized`关键字,作用于整个方法体,锁住的是调用该方法的对象实例。
  
- **代码块同步**:更灵活的使用方式,允许开发者明确指定锁定的对象,形式为`synchronized(对象){...}`。这里的“对象”可以是任何对象实例,最常见的是锁住某个实例或类的Class对象。

#### 2. 工作原理

`synchronized`的实现基于Java对象的监视器锁(Monitor)。当线程试图进入`synchronized`区域时,它首先必须获取锁。如果锁已被其他线程持有,则该线程将被阻塞,直到锁被释放。这一过程确保了同一时刻只有一个线程能执行被保护的代码。

#### 3. 使用示例

##### 方法级同步

```java

public class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}
}


```
在上述示例中,`increment()`和`getCount()`方法都被声明为`synchronized`,这意味着同一时间只有一个线程能访问这些方法,保证了`count`变量的线程安全性。

##### 代码块同步

```java

public class Counter {private int count = 0;private Object lock = new Object();public void safeIncrement() {synchronized(lock) {count++;}}public int safeGetCount() {synchronized(lock) {return count;}}
}


```
这里,我们使用了一个独立的锁对象`lock`来控制同步代码块,这样可以更细粒度地控制锁的范围,提高并发性能。

#### 4. 高级话题

- **锁升级与降级**:在Java 6之后,JVM引入了偏向锁、轻量级锁和重量级锁的概念,以优化synchronized的性能。这一机制根据竞争状况动态调整锁的类型,减少不必要的阻塞。

- **死锁**:不当使用`synchronized`可能导致死锁,即两个或多个线程互相等待对方持有的锁而永久阻塞。设计时应避免嵌套锁,或确保锁的获取顺序一致。

- **可重入性**:synchronized具有可重入性,即同一个线程可以多次获得同一个锁而不被阻塞,这对于递归调用或同步代码中调用其他同步方法至关重要。

#### 5. 总结

`synchronized`关键字是Java并发编程中的基石之一,正确使用它可以有效解决多线程环境下的数据同步问题。理解其背后的工作原理、熟练掌握其应用技巧,对于构建高性能、高可靠的并发系统至关重要。然而,随着并发工具包(java.util.concurrent)的丰富,开发者也应该考虑使用如`ReentrantLock`、`Semaphore`等高级并发工具,以满足更复杂的并发控制需求。总之,选择合适的同步机制,平衡性能与安全性,是每一位Java并发编程者的必修课。

### Java并发高级话题实践:深入ReentrantLock与Condition

在Java并发编程中,虽然`synchronized`关键字提供了基本的同步机制,但对于更复杂的并发控制场景,`java.util.concurrent.locks`包中的`ReentrantLock`和`Condition`接口提供了更为灵活和强大的工具。本节将通过具体代码示例,深入探讨这些高级同步机制的使用。

#### 1. ReentrantLock:可重入的互斥锁

`ReentrantLock`是`synchronized`的一种替代方案,它提供了公平锁和非公平锁的选择,以及尝试获取锁、定时获取锁等高级功能。下面的示例展示了如何使用`ReentrantLock`进行基本的同步控制。

```java

import java.util.concurrent.locks.ReentrantLock;public class BankAccount {private double balance;private final ReentrantLock lock = new ReentrantLock();public BankAccount(double balance) {this.balance = balance;}public void deposit(double amount) {lock.lock();try {if (amount > 0) {balance += amount;}} finally {lock.unlock();}}public void withdraw(double amount) {lock.lock();try {if (amount > 0 && amount <= balance) {balance -= amount;}} finally {lock.unlock();}}public double getBalance() {return balance;}}

```

在上述代码中,`ReentrantLock`被用来保护账户余额的存取操作,确保了并发存款和取款操作的原子性。`lock()`方法用于获取锁,`unlock()`方法用于释放锁,`finally`块确保即使发生异常也能释放锁。

#### 2. Condition:精细的线程协调

`Condition`接口允许线程在满足特定条件时等待,直到其他线程通知条件已满足。它是对传统wait/notify机制的改进,提供了更高的灵活性和清晰性。下面的生产者-消费者模型展示了`Condition`的用法。

```java

import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class BoundedBuffer<T> {private final Queue<T> queue;private final Lock lock;private final Condition notFull;private final Condition notEmpty;private final int capacity;public BoundedBuffer(int capacity) {this.queue = new LinkedList<>();this.lock = new ReentrantLock();this.notFull = lock.newCondition();this.notEmpty = lock.newCondition();this.capacity = capacity;}public void put(T item) throws InterruptedException {lock.lock();try {while (queue.size() == capacity) {notFull.await(); // 当队列满时,生产者等待}queue.offer(item);notEmpty.signal(); // 通知消费者队列中有新元素} finally {lock.unlock();}}public T take() throws InterruptedException {lock.lock();try {while (queue.isEmpty()) {notEmpty.await(); // 当队列空时,消费者等待}T item = queue.poll();notFull.signal(); // 通知生产者队列有空间return item;} finally {lock.unlock();}}}

```

在这个例子中,`BoundedBuffer`类模拟了一个固定容量的缓冲区,生产者线程调用`put()`方法添加元素,消费者线程通过`take()`方法移除元素。`notFull`和`notEmpty`条件分别用于控制生产者在队列满时等待,以及消费者在队列空时等待。

#### 总结

通过`ReentrantLock`和`Condition`,Java并发编程可以达到更细粒度的控制,提供比`synchronized`关键字更丰富的功能和更好的性能。`ReentrantLock`支持公平性选择、尝试获取锁等特性,而`Condition`则允许线程间进行更精确的协调。在设计复杂的并发逻辑时,这些高级工具能够帮助开发者构建更加健壮和高效的并发程序。


http://www.mrgr.cn/p/82624744

相关文章

INS 论文分享:一种用于交通流预测的多通道时空Transformer模型

本文主要介绍了我们在长期交通流预测方面的最新研究成果&#xff0c;该成果已发表在信息学领域的顶级期刊《Information Sciences》上&#xff0c;论文题目为《A Multi-Channel Spatial-Temporal Transformer Model for Traffic Flow Forecasting》。该论文的第一作者及通讯作者…

流媒体学习之路(WebRTC)——GCC中ProbeBitrateEstimator和AcknowledgedBitrateEstimator的大作用(7)

流媒体学习之路(WebRTC)——GCC中ProbeBitrateEstimator和AcknowledgedBitrateEstimator的大作用&#xff08;7&#xff09; —— 我正在的github给大家开发一个用于做实验的项目 —— github.com/qw225967/Bifrost目标&#xff1a;可以让大家熟悉各类Qos能力、带宽估计能力&a…

移动端定位打卡

签到按钮脚本 Mobile_NS.getCurrPosition(function(result){var lngdangq = result["lng"];var lathoum = result["lat"];var minDistance = null;//alert("addr"+addr);var dkzt = $f("dkzt").val();//alert(dkzt);if(dkzt==0){//$f(…

steam错误代码118?报错118?手把手教你应对Steam错误代码攻略

steam是由美国游戏开发公司Valve开发的一款数字发行、数字版权管理、多人游戏和社交平台。它最初是为Valve公司所开发的游戏而设计的&#xff0c;但现在已经发展成为游戏行业最大的数字发行平台之一。Steam平台提供了丰富的游戏资源&#xff0c;包括最新的独立游戏、大型多人在…

3秒修复老照片,一键智能变高清!

你肯定有一些年代久远的老照片,以及网络下载的图片或视频,不够高清还非常模糊,如果能一键修复成高清就好了!现在推荐一款神奇的Real-ESRGAN镜像,可以将模糊老照片和视频修复成高清晰,动动手分分钟帮你一键焕新!操作指南这就马上附上!你肯定有一些年代久远的老照片,以及…

EC11的中断实验——NVICEXTI

本文隶属于《GD32 示波器项目软件部分重难点及相关疑问解决》 4-EC11的中断实验——NVIC&EXTI 4-1 实验目标以及原理图 GD32E230外部中断EXTI(中断/事件控制器)包括21个相互独立的边沿检测电路并且能够向处理器内核产生中断请求或唤醒事件。EXTI有三种触发类型:上升沿触…

使用stable diffusion设计logo的提示词

使用stable diffusion设计logo的提示词 Stable Diffusion是一种基于图像处理和机器学习的算法,可以用于生成各种类型的图像,包括Logo设计。本文将介绍如何使用Stable Diffusion来设计Logo,并提供一些提示词以帮助读者更好地理解和应用这种技术。 1.了解Stable Diffusion的基…

方正字体 3.0 和 5.0 的比较

默认字体就是宋体(方正书宋)主要区别在于英文字体。5.0 中的斜体、宋体、黑体和楷体的英文字体都变化较大。 个人认为 5.0 更为合理。因为斜体和楷体本身就是较为接近手写字体的字体。而 5.0 中的英文斜体和楷体改的更像手写了。

实验四——代码审查

一、实验题目 :代码审查 二、实验目的 1、熟悉编码风格,利用开发环境所提供的平台工具对代码进行自动格式审查; 2、根据代码规范制定代码走查表,并按所制定的审查规范互审代码。 三、实验内容 1、IDEA环境和PyCharm环境二选一; IDEA环境 (1)预先准备在IDEA环境下实现对输…

vue开发网站—①调用$notify弹窗、②$notify弹窗层级问题、③js判断两个数组是否相同等。

一、vue中如何使用vant的 $notify&#xff08;展示通知&#xff09; 在Vue中使用Vant组件库的$notify方法来展示通知&#xff0c;首先确保正确安装了Vant并在项目中引入了Notify组件。 1.安装vant npm install vant --save# 或者使用yarn yarn add vant2.引入&#xff1a;在ma…

nginx--压缩https证书favicon.iconginx隐藏版本号 去掉nginxopenSSL

压缩功能 简介 Nginx⽀持对指定类型的⽂件进行压缩然后再传输给客户端&#xff0c;而且压缩还可以设置压缩比例&#xff0c;压缩后的文件大小将比源文件显著变小&#xff0c;这样有助于降低出口带宽的利用率&#xff0c;降低企业的IT支出&#xff0c;不过会占用相应的CPU资源…

VBA_NZ系列工具NZ06:VBA创建PDF文件说明

我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#xff0c;这么多知识点该如何组织…

ssrf漏洞学习——基础知识

一、SSRF是什么&#xff1f; SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能…

《架构风清扬-Java面试系列第29讲》聊聊DelayQueue的使用场景

DelayQueue是BlockingQueue接口的一个实现类之一 这个属于基础性问题&#xff0c;老规矩&#xff0c;我们将从使用场景和代码示例来进行讲解 来&#xff0c;思考片刻&#xff0c;给出你的答案 1&#xff0c;使用场景 实现&#xff1a;延迟队列&#xff0c;其中元素只有在其预定…

layui的treeTable组件,多层级上传按钮失效的问题解决

现象描述: layui的treeTable 的上传按钮在一层能用&#xff0c;展开后其他按钮正常点击&#xff0c;上传按钮无效。 具体原因没有深究&#xff0c;大概率是展开的子菜单没有被渲染treeTable的done管理到&#xff0c;导致没有重绘上传按钮。 解决方案: 不使用layu的上传组件方法…

springboot+vue快速部署前后台项目,无需服务器

问题 前言 我们都知道,现在的主流开发大多数为,前后端分离,目前流行的框架,大多数是spring boot+element ui 这些框架,这无疑是给开发部署项目带来了便利,我们后台开发无需关心前端如何部署的,前端同样也无需关系后台如何部署,只需要确认能够访问即可。 存在有如下问题…

DDR5和LPDDR4/5 命令解析

关键名称介绍 DDR5 SDRAM和LPDDR4/5都采用了高级的命令集来支持更高效的内存管理和操作,其中“Multi-purpose command (MPC)”、“Mode Register Read (MRR)”、“Mode Register Write (MRW)”,以及“Write Pattern Command”是几种关键的命令类型,它们在内存初始化、配置和…

大型语言模型的新挑战:AMR语义表示的神秘力量

DeepVisionary 每日深度学习前沿科技推送&顶会论文&数学建模与科技信息前沿资讯分享&#xff0c;与你一起了解前沿科技知识&#xff01; 引言&#xff1a;AMR在大型语言模型中的作用 在自然语言处理&#xff08;NLP&#xff09;的领域中&#xff0c;抽象意义表示&…

HBM供不应求,SK海力士称2025年订单都几乎售罄

【科技明说 &#xff5c; 科技热点关注】 据外媒报道&#xff0c;SK海力士透露公司今年的HBM产能已经全部售罄&#xff0c;明年订单也基本售罄。此外&#xff0c;SK海力士预计在2024年5月提供世界最高性能的12层堆叠HBM3E产品的样品&#xff0c;并准备在第三季度开始量产。 ​…