IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java多线程并发编程实战之高并发数据一致性实战 -> 正文阅读

[Java知识库]Java多线程并发编程实战之高并发数据一致性实战

出自:

腾讯课堂 700多分钟干货实战Java多线程高并发高性能实战全集 , 我学习完了之后, 我给 老师在课上说的话做了个笔记,以及视频的内容,还有代码敲了一遍,然后添加了一些注释,把执行结果也整理了一下, 做了个笔记

案例背景

在实际研发场景中,经常会出现并发数据一致性的问题,如果解决不好,会导致数据逻辑发生错误.

假设有这种并发场景:A用户开了一个银行账户,账户初始金额为10000元,另外会计张三每隔一段时间向该账户转账100元,账户余额上限是20000元.另外用两个用户李四和王五每隔一段时间并发地从该账户分别取款100元,200元,直到账户总金额为0结束并发.

如果你是架构师,在上述多种角色并发操作账户金额的技术场景下,请运用多线程并发编程等相关基础知识实现账户金额数据的一致性问题.

解决方法

用原子类,这样多个线程操作同一个数据就不会出现数据错乱的问题.
?

代码地址

https://gitee.com/zjj19941/mutil-thread/tree/master/src/main/java/com/yrxy/thread/case6
?

代码

账户类

import java.util.concurrent.atomic.AtomicInteger;

public class Account {
    // 声明一个原子类, 多个线程操作这个变量是线程安全的
    private AtomicInteger amount;

    private String name;

    public void name() {
        System.out.println("账户为:" + name + "!");
    }

    /**
     * 存款方法
     */
    public synchronized boolean deposit(String threadName, int change) {

        amount.addAndGet(change);
        // 账户余额上限是20000元 ,超过金额就不让存了
        if (amount.get() > 20000) {
            System.out.print("存款金额已经达到上限,存款失败");
            return false;
        }
        System.out.println("01:" + threadName + ",存款金额为" + change + ",开始存款,存款后余额为" + amount);
        return true;
    }

    /**
     * 取款
     */
    public synchronized boolean withdraw(String threadName, int money) {
        if (amount.get() <= 0 || amount.get() < money) {  // 如果取款金额大于账户的余额
            System.out.println(threadName + ",账户金额为" + amount.get() + ",你的取款金额为" + money + ",取款失败");
            return false;
        } else {
            amount.addAndGet(-money);  //取款操作
            System.out.println("02:" + threadName + ",取款金额为" + money + ",开始取款,取款后余额为" + amount);
            return true;
        }
    }

    /**
     * 开户
     */
    public void openAccount(String name, Integer money) {
        this.name = name;
        this.amount = new AtomicInteger(money);
        System.out.println("00:" + name + "开户成功,开户金额为" + money);
    }

    public AtomicInteger getAmount() {
        return amount;
    }

//    public void setAmount(AtomicInteger amount) {
//        this.amount = amount;
//    }
}

存款的并发线程类

import java.util.Random;

/**
 * 存款的并发线程类
 */
public class Deposit implements Runnable {

    private Account account;

    private int deposit;

    public void deposit(Account account, int deposit) {
        this.account = account;
        this.deposit = deposit;
    }


    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        while (true) {

            if (account.getAmount().get() < 20000) { //账号金额少于20000元就允许存款


                // 存款方法
                boolean isFlag = account.deposit(threadName, deposit);
                if (!isFlag) {
                    break;
                }
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (account.getAmount().get() >= 20000) {
                break;
            }
            if (account.getAmount().get() == 0) {
                System.out.println("余额为零,存款结束");
                break;
            }
        }
    }

}

取款的线程类

import java.util.Random;

/**
 * 取款的线程类
 */
public class Withdraw implements Runnable {

    private Account account;

    private int withdraw;

    public void withdraw(Account account, int withdraw) {
        this.account = account;
        this.withdraw = withdraw;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        while (true) {
            if (account.getAmount().get() > 0) {
                // 取款
                boolean isFlag = account.withdraw(threadName, withdraw);
                if (!isFlag) {
                    break;
                }

                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            } else {

                break;
            }
        }
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        // 开户,账户一万元
        Account account = new Account();
        account.openAccount("黄老邪", 10000);
        //存款
        Deposit p1 = new Deposit();
        p1.deposit(account, 100);
        Thread depositThread = new Thread(p1, "张三");
        //取100元
        Withdraw p2 = new Withdraw();
        p2.withdraw(account, 100);
        Thread withdrawThread1 = new Thread(p2, "李四");
        //取200元
        Withdraw p3 = new Withdraw();
        p3.withdraw(account, 200);
        Thread withdrawThread2 = new Thread(p3, "王五");
        withdrawThread1.start();
        withdrawThread2.start();
        depositThread.start();
    }

}

执行测试类控制台输出结果

00:黄老邪开户成功,开户金额为10000
02:李四,取款金额为100,开始取款,取款后余额为9900
02:王五,取款金额为200,开始取款,取款后余额为9700
01:张三,存款金额为100,开始存款,存款后余额为9800
02:李四,取款金额为100,开始取款,取款后余额为9700
02:李四,取款金额为100,开始取款,取款后余额为9600
01:张三,存款金额为100,开始存款,存款后余额为9700
02:王五,取款金额为200,开始取款,取款后余额为9500
02:李四,取款金额为100,开始取款,取款后余额为9400
01:张三,存款金额为100,开始存款,存款后余额为9500
02:李四,取款金额为100,开始取款,取款后余额为9400
02:王五,取款金额为200,开始取款,取款后余额为9200
01:张三,存款金额为100,开始存款,存款后余额为9300
01:张三,存款金额为100,开始存款,存款后余额为9400
02:李四,取款金额为100,开始取款,取款后余额为9300
01:张三,存款金额为100,开始存款,存款后余额为9400
02:王五,取款金额为200,开始取款,取款后余额为9200
02:李四,取款金额为100,开始取款,取款后余额为9100
01:张三,存款金额为100,开始存款,存款后余额为9200
01:张三,存款金额为100,开始存款,存款后余额为9300
02:李四,取款金额为100,开始取款,取款后余额为9200
02:王五,取款金额为200,开始取款,取款后余额为9000
01:张三,存款金额为100,开始存款,存款后余额为9100
02:李四,取款金额为100,开始取款,取款后余额为9000
02:王五,取款金额为200,开始取款,取款后余额为8800
01:张三,存款金额为100,开始存款,存款后余额为8900
01:张三,存款金额为100,开始存款,存款后余额为9000
02:李四,取款金额为100,开始取款,取款后余额为8900
02:王五,取款金额为200,开始取款,取款后余额为8700
02:王五,取款金额为200,开始取款,取款后余额为8500
01:张三,存款金额为100,开始存款,存款后余额为8600
02:王五,取款金额为200,开始取款,取款后余额为8400
02:李四,取款金额为100,开始取款,取款后余额为8300
02:李四,取款金额为100,开始取款,取款后余额为8200
02:李四,取款金额为100,开始取款,取款后余额为8100
02:王五,取款金额为200,开始取款,取款后余额为7900
01:张三,存款金额为100,开始存款,存款后余额为8000
02:李四,取款金额为100,开始取款,取款后余额为7900
01:张三,存款金额为100,开始存款,存款后余额为8000
01:张三,存款金额为100,开始存款,存款后余额为8100
02:李四,取款金额为100,开始取款,取款后余额为8000
02:王五,取款金额为200,开始取款,取款后余额为7800
01:张三,存款金额为100,开始存款,存款后余额为7900
02:王五,取款金额为200,开始取款,取款后余额为7700
02:王五,取款金额为200,开始取款,取款后余额为7500
02:李四,取款金额为100,开始取款,取款后余额为7400
02:王五,取款金额为200,开始取款,取款后余额为7200
01:张三,存款金额为100,开始存款,存款后余额为7300
02:李四,取款金额为100,开始取款,取款后余额为7200
02:李四,取款金额为100,开始取款,取款后余额为7100
02:王五,取款金额为200,开始取款,取款后余额为6900
02:王五,取款金额为200,开始取款,取款后余额为6700
02:李四,取款金额为100,开始取款,取款后余额为6600
01:张三,存款金额为100,开始存款,存款后余额为6700
01:张三,存款金额为100,开始存款,存款后余额为6800
02:李四,取款金额为100,开始取款,取款后余额为6700
02:李四,取款金额为100,开始取款,取款后余额为6600
02:王五,取款金额为200,开始取款,取款后余额为6400
02:王五,取款金额为200,开始取款,取款后余额为6200
01:张三,存款金额为100,开始存款,存款后余额为6300
02:王五,取款金额为200,开始取款,取款后余额为6100
02:李四,取款金额为100,开始取款,取款后余额为6000
02:王五,取款金额为200,开始取款,取款后余额为5800
02:李四,取款金额为100,开始取款,取款后余额为5700
01:张三,存款金额为100,开始存款,存款后余额为5800
01:张三,存款金额为100,开始存款,存款后余额为5900
02:王五,取款金额为200,开始取款,取款后余额为5700
01:张三,存款金额为100,开始存款,存款后余额为5800
01:张三,存款金额为100,开始存款,存款后余额为5900
02:李四,取款金额为100,开始取款,取款后余额为5800
01:张三,存款金额为100,开始存款,存款后余额为5900
02:李四,取款金额为100,开始取款,取款后余额为5800
02:王五,取款金额为200,开始取款,取款后余额为5600
01:张三,存款金额为100,开始存款,存款后余额为5700
02:李四,取款金额为100,开始取款,取款后余额为5600
02:王五,取款金额为200,开始取款,取款后余额为5400
02:李四,取款金额为100,开始取款,取款后余额为5300
02:王五,取款金额为200,开始取款,取款后余额为5100
02:李四,取款金额为100,开始取款,取款后余额为5000
01:张三,存款金额为100,开始存款,存款后余额为5100
02:李四,取款金额为100,开始取款,取款后余额为5000
02:王五,取款金额为200,开始取款,取款后余额为4800
01:张三,存款金额为100,开始存款,存款后余额为4900
02:李四,取款金额为100,开始取款,取款后余额为4800
02:王五,取款金额为200,开始取款,取款后余额为4600
01:张三,存款金额为100,开始存款,存款后余额为4700
01:张三,存款金额为100,开始存款,存款后余额为4800
02:李四,取款金额为100,开始取款,取款后余额为4700
02:王五,取款金额为200,开始取款,取款后余额为4500
02:李四,取款金额为100,开始取款,取款后余额为4400
01:张三,存款金额为100,开始存款,存款后余额为4500
02:王五,取款金额为200,开始取款,取款后余额为4300
02:李四,取款金额为100,开始取款,取款后余额为4200
01:张三,存款金额为100,开始存款,存款后余额为4300
02:王五,取款金额为200,开始取款,取款后余额为4100
02:王五,取款金额为200,开始取款,取款后余额为3900
02:李四,取款金额为100,开始取款,取款后余额为3800
02:李四,取款金额为100,开始取款,取款后余额为3700
01:张三,存款金额为100,开始存款,存款后余额为3800
01:张三,存款金额为100,开始存款,存款后余额为3900
01:张三,存款金额为100,开始存款,存款后余额为4000
02:王五,取款金额为200,开始取款,取款后余额为3800
02:李四,取款金额为100,开始取款,取款后余额为3700
02:王五,取款金额为200,开始取款,取款后余额为3500
01:张三,存款金额为100,开始存款,存款后余额为3600
02:李四,取款金额为100,开始取款,取款后余额为3500
02:李四,取款金额为100,开始取款,取款后余额为3400
02:王五,取款金额为200,开始取款,取款后余额为3200
02:李四,取款金额为100,开始取款,取款后余额为3100
01:张三,存款金额为100,开始存款,存款后余额为3200
02:王五,取款金额为200,开始取款,取款后余额为3000
02:李四,取款金额为100,开始取款,取款后余额为2900
02:王五,取款金额为200,开始取款,取款后余额为2700
02:王五,取款金额为200,开始取款,取款后余额为2500
02:李四,取款金额为100,开始取款,取款后余额为2400
01:张三,存款金额为100,开始存款,存款后余额为2500
02:王五,取款金额为200,开始取款,取款后余额为2300
02:李四,取款金额为100,开始取款,取款后余额为2200
02:王五,取款金额为200,开始取款,取款后余额为2000
02:李四,取款金额为100,开始取款,取款后余额为1900
01:张三,存款金额为100,开始存款,存款后余额为2000
02:王五,取款金额为200,开始取款,取款后余额为1800
02:李四,取款金额为100,开始取款,取款后余额为1700
01:张三,存款金额为100,开始存款,存款后余额为1800
02:王五,取款金额为200,开始取款,取款后余额为1600
02:李四,取款金额为100,开始取款,取款后余额为1500
02:王五,取款金额为200,开始取款,取款后余额为1300
02:李四,取款金额为100,开始取款,取款后余额为1200
01:张三,存款金额为100,开始存款,存款后余额为1300
02:王五,取款金额为200,开始取款,取款后余额为1100
02:李四,取款金额为100,开始取款,取款后余额为1000
02:王五,取款金额为200,开始取款,取款后余额为800
02:王五,取款金额为200,开始取款,取款后余额为600
01:张三,存款金额为100,开始存款,存款后余额为700
02:李四,取款金额为100,开始取款,取款后余额为600
02:王五,取款金额为200,开始取款,取款后余额为400
01:张三,存款金额为100,开始存款,存款后余额为500
02:李四,取款金额为100,开始取款,取款后余额为400
02:王五,取款金额为200,开始取款,取款后余额为200
02:王五,取款金额为200,开始取款,取款后余额为0
余额为零,存款结束
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-05 21:35:51  更:2022-02-05 21:38:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:59:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码