Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件

这篇具有很好参考价值的文章主要介绍了Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引出


1.大量请求拥挤抢购中的数据不安全问题;
2.事务ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability);
3.线程安全特征:原子性(Atomicity)可见性(Visibility)有序性(Ordering);
4.java中的锁初步,synchronize锁和ReentrantLock锁使用初步;
5.滥用锁的问题,以及产生死锁的条件;

场景:大量请求拥挤抢购

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

package com.tianju.redis.service.impl;

import com.tianju.redis.service.IRushGoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RushGoodsServiceImpl implements IRushGoodsService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String GOODS = "goods";

    @Override
    public String rush() {
        String sNum = stringRedisTemplate.opsForValue().get(GOODS);
        int nums = Integer.parseInt(sNum);
        if (nums>0){
            stringRedisTemplate.opsForValue().set(GOODS, String.valueOf(--nums) );
            return stringRedisTemplate.opsForValue().get(GOODS);
        }else {
            return "error";
        }
    }
}
    @PutMapping("/rushJmeter")
    public void rushJmeter(){
        String goodsNum = rushGoodsService.rush();
        System.out.println("goodsNum: "+goodsNum);
    }

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

事务的基本特征ACID

事务是指一组操作被视为一个不可分割的工作单元,要么全部执行成功,要么全部不执行。事务具有以下四个基本特征,通常被称为ACID特性:

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

  • 原子性(Atomicity):事务是一个原子操作,要么全部执行成功,要么全部不执行。如果事务中的任何一个操作失败,整个事务将被回滚到初始状态,不会对数据库产生任何影响。

  • 一致性(Consistency):事务在执行前和执行后,数据库的状态必须保持一致。这意味着事务中的操作必须满足数据库的完整性约束,包括唯一性约束、外键约束等。

  • 隔离性(Isolation):事务的执行是相互隔离的,一个事务的操作不会被其他事务所干扰。隔离性确保了并发执行的事务之间不会产生不一致的结果。

  • 持久性(Durability):一旦事务提交成功,其所做的修改将永久保存在数据库中,即使系统发生故障或重启,修改的结果也不会丢失。

这些特性确保了事务的可靠性和一致性。数据库管理系统通过使用日志和锁等机制来实现事务的特性。在设计和实现数据库应用程序时,需要考虑事务的边界和正确使用事务来保证数据的完整性和一致性

线程安全的基本特征

线程安全是指在多线程环境下,对共享资源的访问和操作不会导致数据不一致或产生不可预期的结果。线程安全的基本特征包括:

  • 原子性(Atomicity):对共享资源的操作要么全部执行成功,要么全部不执行,不存在中间状态。即使在多线程环境下,也能保证操作的完整性。简单说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现

  • 可见性(Visibility):一个线程对共享资源的修改对其他线程是可见的。当一个线程修改了共享资源的值后,其他线程能够立即看到最新的值。可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile就是负责保证可见性的。

  • 有序性(Ordering):线程的执行顺序与程序的代码顺序一致。即使在多线程环境下,也能保证操作按照预期的顺序执行。是保证线程内串行语义,避免指令重排等。

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言
解决办法

  • 使用互斥锁(Mutex)或信号量(Semaphore)等同步机制,确保在同一时间只有一个线程能够访问共享资源。

  • 使用原子操作(Atomic Operation)来保证对共享资源的操作是原子的,不会被其他线程中断。

  • 使用volatile关键字来保证共享变量的可见性,确保一个线程对共享变量的修改对其他线程是可见的。

  • 使用线程安全的数据结构或类,这些数据结构或类已经在设计上考虑了多线程环境下的安全性。

加锁(java)

synchronized锁

可重入锁: sychronized ReentrantLock

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

synchronized (this.getClass()){}

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

ReentrantLock锁

private final ReentrantLock lock = new ReentrantLock(); // 可重入锁

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

什么是可重入锁?

当线程获取某个锁后,还可以继续获取它,可以递归调用,而不会发生死锁;

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

如何保证可重入

当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁

如果测试成功,表示线程已经获得了锁。
如果测试失败,则需要再测试一下Mark Word中偏向锁标志是否设置成1:没有则CAS竞争;设置了,则CAS将对象头偏向锁指向当前线程。再维护一个计数器,同个线程进入则自增1,离开再减1,直到为0才能释放

滥用锁的代价?(死锁)

死锁的四个必要条件

循环 A —> B —>C —>A

产生死锁的必要条件是以下四个条件同时满足:

  • 互斥条件(Mutual Exclusion):至少有一个资源被一个进程独占使用,即在一段时间内只能由一个进程访问。

  • 请求与保持条件(Hold and Wait):一个进程在持有至少一个资源的同时,又请求获取其他进程持有的资源。

  • 不可剥夺条件(No Preemption):资源只能由持有者显式地释放,其他进程无法强制剥夺。

  • 循环等待条件(Circular Wait):存在一个进程资源的循环链,每个进程都在等待下一个进程所持有的资源。

当这四个条件同时满足时,就可能发生死锁。如果任何一个条件不满足,就不会发生死锁。

死锁是多线程或多进程并发执行时的一种常见问题,它会导致系统无法继续执行下去,需要通过死锁检测、死锁预防、死锁避免或死锁解除等方法来处理。

死锁的案例

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

可能导致死锁

Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件,Java,java,安全,开发语言

锁对象ObjLock

package com.tianju.redis.lock;

public class ObjLock {
    private String name;

    public ObjLock(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "ObjLock:"+this.name;
    }
}

加锁释放锁方法DeadLockDemo

package com.tianju.redis.lock;

public class DeadLockDemo {

    private ObjLock a;
    public ObjLock b;

    public DeadLockDemo(ObjLock a,ObjLock b){
        this.a = a;
        this.b = b;
    }

    public void dead(){
        System.out.println("********"+a+"对象"+b+"对象都加锁**************");
        System.out.println(a+"--"+b+": "+"准备给"+a+"对象加锁>>");
        synchronized (a){
            System.out.println(a+"--"+b+": "+a+"对象加锁成功...");
            System.out.println(a+"--"+b+": "+"准备给"+b+"对象加锁>>>");
            synchronized (b){
                System.out.println(a+"--"+b+": "+b+"对象加锁成功");
            }
            System.out.println(a+"--"+b+": "+"释放"+b+"对象的锁");
        }
        System.out.println(a+"--"+b+": "+"释放"+b+"对象的锁");
        System.out.println("****************");
    }
}

测试方法

package com.tianju.redis.lock;

public class TestDeadLock {

    /**
     * 一个一个顺序运行
     */
    public static void run(){
        ObjLock a = new ObjLock("A");
        ObjLock b = new ObjLock("B");
        ObjLock c = new ObjLock("C");

        DeadLockDemo lockDemo1 = new DeadLockDemo(a, b);
        lockDemo1.dead(); // 锁住a和b

        DeadLockDemo lockDemo2 = new DeadLockDemo(b, c);
        lockDemo2.dead(); // 锁住a和b

        DeadLockDemo lockDemo3 = new DeadLockDemo(c, a);
        lockDemo3.dead(); // 锁住a和b
    }

    /**
     * 进行线程抢,死锁
     */
    public static void rushRun(){
        ObjLock a = new ObjLock("A");
        ObjLock b = new ObjLock("B");
        ObjLock c = new ObjLock("C");

        new Thread(()->{
            DeadLockDemo lockDemo1 = new DeadLockDemo(a, b);
            lockDemo1.dead(); // 锁住a和b
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        new Thread(()->{
            DeadLockDemo lockDemo2 = new DeadLockDemo(b, c);
            lockDemo2.dead(); // 锁住a和b
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        new Thread(()->{
            DeadLockDemo lockDemo3 = new DeadLockDemo(c, a);
            lockDemo3.dead(); // 锁住a和b
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }


    public static void main(String[] args) {
//        run(); // 顺序执行加锁,解锁
        rushRun(); // 线程进行抢
    }
}


总结

1.大量请求拥挤抢购中的数据不安全问题;
2.事务ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability);
3.线程安全特征:原子性(Atomicity)可见性(Visibility)有序性(Ordering);
4.java中的锁初步,synchronize锁和ReentrantLock锁使用初步;
5.滥用锁的问题,以及产生死锁的条件;文章来源地址https://www.toymoban.com/news/detail-673771.html

到了这里,关于Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java 进阶篇】Redis持久化之RDB:数据的安全守护者

    Redis,作为一款高性能的键值存储系统,支持多种持久化方式,其中RDB(Redis DataBase)是其最常用的一种。RDB可以将当前时刻的数据快照保存到磁盘,以便在Redis重启时快速恢复数据。本文将深入探讨RDB的原理、配置和实际应用,帮助初学者更好地理解和使用Redis的持久化机制

    2024年02月05日
    浏览(48)
  • 【多线程进阶】synchronized 原理

    在前面章节中, 提到了多线程中的锁策略, 那么我们 Java 中的锁 synchronized 背后都采取了哪些锁策略呢? 又是如何进行工作的呢? 本节我们就来谈一谈. 关注收藏, 开始学习吧🧐 在 Java 中, synchronized 具有以下特性(这里以 JDK 1.8 为例): 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲

    2024年02月07日
    浏览(34)
  • 【六大锁策略-各种锁的对比-Java中的Synchronized锁和ReentrantLock锁的特点分析-以及加锁的合适时机】

    阅读该文章之前要了解,锁策略是为了解决什么问题 多线程带来的的风险-线程安全的问题的简单实例-线程不安全的原因 提示:以下是本篇文章正文内容,下面案例可供参考 锁冲突是指两个线程对一个对象加锁,产生了阻塞等待。 乐观锁 假设数据一般情况下不会产生并发冲

    2024年02月15日
    浏览(66)
  • Java进阶(3)——手动实现ArrayList & 源码的初步理解分析 & 数组插入数据和删除数据的问题

    1.ArrayList的结构分析,可迭代接口,是List的实现; 2.数组增加元素和删除元素的分析,何时扩容,如何扩容; 3.插入数据的复杂度O(N); 4.数组特点:查找和修改容易O(1);增加和删除复杂O(N); 增加元素 如果放不下怎么办?如何扩容? 扩容后如何操作? 扩容:每次为原来的

    2024年02月12日
    浏览(42)
  • 智能建筑中的大数据分析:概述,应用,安全和隐私问题

    作者:禅与计算机程序设计艺术 近年来,智能建筑、智慧城市等新兴的概念层出不穷,人们对智能建筑、智慧城市追求的是从根本上解决环境问题、提升社会生活品质、实现经济社会效益的目标。智能建筑可谓是国际化进程中最具代表性的新兴产业领域之一。智能建筑即“未

    2024年02月15日
    浏览(45)
  • 跨域问题未解决:策略未能处理跨域数据交换中的安全风险

    随着互联网的快速发展,不同组织之间的信息交流和协作变得越来越频繁。在这个过程中,安全成为了一个重要的话题。特别是当涉及到跨领域数据处理时(如来自不同网站、应用或云服务器的数据),如何保护这些数据的完整性和安全性显得尤为重要。然而在实际情况下,许

    2024年02月02日
    浏览(37)
  • 【JavaEE初阶】多线程进阶(五)常见锁策略 CAS synchronized优化原理

    乐观锁:预测锁竞争不是很激烈。 悲观锁:预测锁竞争会很激烈。 以上定义并不是绝对的,具体看预测锁竞争激烈程度的结论。 轻量级锁加锁解锁开销比较小,效率更高。 重量级锁加锁解锁开销比较大,效率更低。 多数情况下,乐观锁也是一个轻量级锁。 多数情况下,悲

    2024年02月03日
    浏览(46)
  • Java中的线程池技术进阶

    Java中的线程池技术是用于管理和复用线程的一种技术,它可以有效地提高应用程序的性能和响应速度。在Java中,线程池可以通过java.util.concurrent包中的ExecutorService接口和相关实现类来创建和使用。 以下是一些关于Java线程池技术的进阶知识: 线程池参数配置: corePoolSize:核

    2024年01月20日
    浏览(36)
  • 【javaEE面试题(四)线程不安全的原因】【1. 修改共享数据 2. 操作不是原子性 3. 内存可见性 4. 代码顺序性】

    大家观察下是否适用多线程的现象是否一致?同时尝试思考下为什么会有这样的现象发生呢? 原因是 1.load 2. add 3. save 注意:可能会导致 小于5w 想给出一个线程安全的确切定义是复杂的,但我们可以这样认为: 如果多线程环境下代码运行的结果是符合我们预期的,即在单线

    2024年02月13日
    浏览(42)
  • Java网络爬虫——jsoup快速上手,爬取京东数据。同时解决‘京东安全’防爬问题

    网络爬虫,就是在 浏览器上,代替人类爬取数据 ,Java网络爬虫就是通过Java编写爬虫代码,代替人类从网络上爬取信息数据。程序员通过设定既定的规则,让程序代替我们从网络上获取海量我们需要的数据,比如图片,企业信息等。 爬虫的关键是对于网页信息的解析。 什么

    2024年02月10日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包