iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >Java多线程 - 线程安全和线程同步解决线程安全问题
  • 810
分享到

Java多线程 - 线程安全和线程同步解决线程安全问题

java安全jvm 2023-08-20 22:08:51 810人浏览 八月长安
摘要

文章目录 线程安全问题线程同步方式一: 同步代码块方式二: 同步方法方式三: Lock锁 线程安全问题 线程安全问题指的是: 多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题。 举例:

线程安全问题

线程安全问题指的是: 多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题。

举例: 取钱模型演示

需求:小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元。

如果小明和小红同时来取钱,而且2人都要取钱10万元,可能出现什么问题呢?

在这里插入图片描述

在取钱之前都需要判断余额是否足够, 例如两个线程同时执行, 两个线程都进行了余额判断, 发现余额充足;

此时小明线程取走10万, 账户余额为0; 小红线程由于此时已经判断过余额, 继续取钱的时候就不会继续判断余额, 直接将余额取出来; 那么两个人都取走了10万, 银行就亏了10万, 这就是多线程带来的安全问题

线程安全问题模拟, 我们将上面的例子用代码模拟出来多线程的安全隐患:

需求:

小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元,模拟2人同时去取钱10万。

分析:

  1. 需要提供一个账户类,创建一个账户对象代表2个人的共享账户。
  2. 需要定义一个线程类,线程类可以处理账户对象。
  3. 创建2个线程对象,传入同一个账户对象。
  4. 启动2个线程,去同一个账户对象中取钱10万。

实现步骤:

模拟一个账户类给小明线程和小红线程, 我们模拟关键信息即可

public class Account {    private double money;    public  Account() {}    public Account(double money) {        this.money = money;    }        public void drawMoney(double money) {        // 获取取钱人的名字        String name = Thread.currentThread().getName();        if (this.money >= money) { // 判断余额是否充足            System.out.println(name + "取走了" + money + "元");            this.money -= money;        } else {            System.out.println("余额不足");        }    }    public double getMoney() {        return money;    }    public void setMoney(double money) {        this.money = money;    }}

定义一个线程类用来处理账户对象

public class DrawThread extends Thread {    private Account acc;    public DrawThread(Account acc, String name) {        super(name);        this.acc = acc;    }    @Override    public void run() {        acc.drawMoney(100000);    }}

在主类中, 创建2个线程对象,传入同一个账户对象; 启动2个线程,去同一个账户对象中取钱10万

public class ThreadDemo {    public static void main(String[] args) throws Exception {        // 创建账户对象        Account acc = new Account(100000);        // 创建两个子线程, 并启动线程        new DrawThread(acc, "小明").start(); // 小明取走了100000.0元        new DrawThread(acc, "小红").start(); // 小红取走了100000.0元        // 主线程睡眠两秒后, 查看余额        Thread.sleep(2000);        System.out.println(acc.getMoney()); // -100000.0    }}

线程同步

为了解决上面线程安全的问题。

取钱案例出现问题的原因

多个线程同时执行,发现账户都是够钱的。

如何才能保证线程安全呢

让多个线程实现先后依次排队访问共享资源,这样就解决了安全问题

线程同步的核心:

线程同步的核心是加锁,把共享资源进行上,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

加锁的方式有三种方式: 同步代码块, 同步方法和Lock锁, 下面我们来分别学习加锁的方法

方式一: 同步代码块

作用:将出现线程安全问题的核心代码给上锁

原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。

同步代码块上锁的格式:

synchronized(同步锁对象) {  // 操作共享资源的代码(核心代码)}

例如我们给上面模拟的线程安全例子中的核心代码进行加锁操作:

进行加锁操作就解决了线程安全问题

public class Account {    private double money;    public  Account() {}    public Account(double money) {        this.money = money;    }        public void drawMoney(double money) {        String name = Thread.currentThread().getName();        // 对核心代码进行加锁, 这里锁对象随便使用了一个字符串模拟(无实际代表意义)        synchronized ("chen") {            if (this.money >= money) {                System.out.println(name + "取走了" + money + "元");                this.money -= money;            } else {                System.out.println("余额不足");            }        }    }    public double getMoney() {        return money;    }    public void setMoney(double money) {        this.money = money;    }}

锁对象注意:

理论上:锁对象只要对于当前同时执行的线程来说是唯一的一个对象即可。

但是实际上使用任意唯一的锁对象并不好, 会影响其他无关线程的执行, 例如上面例子中, 会将其他无关的账户也锁起来。

锁对象的规范要求:

规范上:建议使用共享资源作为锁对象。

  • 对于实例方法中, 建议使用this作为锁对象。
// 加锁, 使用共享资源作为锁对象synchronized (this) {}
  • 对于静态方法中, 建议使用字节码(类名.class)对象作为锁对象。
// 加锁, 使用共享资源作为锁对象synchronized (类名.class) {}

方式二: 同步方法

作用: 将出现线程安全问题的核心方法给上锁

原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

同步方法的上锁格式:

修饰符 synchronized 返回值类型 方法名称(形参列表) {  // 操作共享资源的代码}

同步方法上锁演示代码:

// 给核心方法上锁public synchronized void drawMoney(double money) {    String name = Thread.currentThread().getName();    if (this.money >= money) {        System.out.println(name + "取走了" + money + "元");        this.money -= money;    } else {        System.out.println("余额不足");    }}

同步方法底层原理:

同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。

如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象

如果方法是静态方法:同步方法默认用类名.class作为的锁对象。

方式三: Lock锁

Lock锁

为了更清晰的表达如何加锁和释放锁,jdk5以后提供了一个新的锁对象Lock,更加灵活、方便。

Lock实现提供比使用synchronized方法和语句可以获得更广泛灵活的锁定操作。

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象。

方法名称说明
ReentrantLock()获得Lock锁的实现类对象

Lock的API:

方法名称说明
lock()获得锁
unlock()释放锁

Lock使用演示代码:

基本使用如下, 我们可以看出Lock使用是非常灵活的

public class Account {    private double money;    // 定义一个示例变量锁对象, 每创建一个类就会创建一个锁对象, 加final修饰, 表示不可替换    private final Lock lock = new ReentrantLock();    public  Account() {}    public Account(double money) {        this.money = money;    }        public synchronized void drawMoney(double money) {        String name = Thread.currentThread().getName();        // 调用锁对象上锁        lock.lock();        if (this.money >= money) {            System.out.println(name + "取走了" + money + "元");            this.money -= money;        } else {            System.out.println("余额不足");        }        // 调用锁对象解锁        lock.unlock();    }    public double getMoney() {        return money;    }    public void setMoney(double money) {        this.money = money;    }}

但是如果我们上锁和解锁之间的代码出现了异常, 永远都不会执行解锁操作, 所以更严谨的写法是将解锁的操作放到try…finally中, 保证会执行解锁的操作

public synchronized void drawMoney(double money) {    String name = Thread.currentThread().getName();    // 调用锁对象上锁    try {        lock.lock();        if (this.money >= money) {            System.out.println(name + "取走了" + money + "元");            this.money -= money;        } else {            System.out.println("余额不足");        }    } finally {        // 调用锁对象解锁        lock.unlock();    }}

来源地址:https://blog.csdn.net/m0_71485750/article/details/127660840

--结束END--

本文标题: Java多线程 - 线程安全和线程同步解决线程安全问题

本文链接: https://www.lsjlt.com/news/376669.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java多线程 - 线程安全和线程同步解决线程安全问题
    文章目录 线程安全问题线程同步方式一: 同步代码块方式二: 同步方法方式三: Lock锁 线程安全问题 线程安全问题指的是: 多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题。 举例:...
    99+
    2023-08-20
    java 安全 jvm
  • Java使用线程同步解决线程安全问题详解
    第一种方法:同步代码块: 作用:把出现线程安全的核心代码上锁 原理:每次只能一个线程进入,执行完毕后自行解锁,其他线程才能进来执行 锁对象要求:理论上,锁对象只要对于当前同时执行的线...
    99+
    2022-11-13
  • Java多线程之线程安全问题
    文章目录 一. 线程安全概述1. 什么是线程安全问题2. 一个存在线程安全问题的程序 二. 线程不安全的原因和线程加锁1. 案例分析2. 线程加锁2.1 理解加锁2.2 synchroni...
    99+
    2023-09-21
    java 线程安全 多线程 synchronized jvm
  • Java多线程之线程安全问题详解
    目录1. 什么是线程安全和线程不安全?2. 自增运算为什么不是线程安全的?3. 临界区资源和竞态条件总结:面试题: 什么是线程安全和线程不安全?自增运算是不是线程安全的?如何保证多线...
    99+
    2022-11-13
  • Java多线程之线程安全问题怎么解决
    本篇内容主要讲解“Java多线程之线程安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程之线程安全问题怎么解决”吧!1.线程安全概述1.1什么是线程安全问题首先我们需要...
    99+
    2023-06-30
  • Java多线程之线程安全问题详情
    目录1.线程安全概述1.1什么是线程安全问题1.2一个存在线程安全问题的程序2.线程加锁与线程不安全的原因2.1案例分析2.2线程加锁2.2.1什么是加锁2.2.2如何加锁2.2.3...
    99+
    2022-11-13
  • Java线程安全与非线程安全解析
    ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题。面对这样的问题,回答是:ArrayList是非线...
    99+
    2023-05-31
    java 线程安全 ava
  • Java多线程下解决数据安全问题
    目录同步代码块同步方法lock锁同步代码块 基本语句 synchronized (任意对象) { 操作共享代码 } 代码示例 public class SellTicket ...
    99+
    2022-11-12
  • Java中线程安全问题
    目录一.线程不安全二.那些情况导致了线程不安全?三.Java中解决线程不安全的方案1.volatile“轻量级”解决线程不安全2.synchronized自动加锁四.公平锁与非公平锁...
    99+
    2022-11-12
  • Java多线程中线程安全问题的示例分析
    这篇文章主要介绍了Java多线程中线程安全问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 什么是线程安全和线程不安全?什么是线程安全呢?当多个线程并发访问某...
    99+
    2023-06-29
  • JAVA多线程线程安全性基础
    目录线程安全性什么是线程安全的代码什么是线程安全性 总结线程安全性 一个对象是否需要是线程安全的,取决于它是否被多个线程访问,而不取决于对象要实现的功能 什么是线程安全的代码 核心:...
    99+
    2022-11-12
  • java多线程创建及线程安全详解
    什么是线程 线程被称为轻量级进程,是程序执行的最小单位,它是指在程序执行过程中,能够执行代码的一个执行单位。每个程序程序都至少有一个线程,也即是程序本身。 线程...
    99+
    2022-11-12
  • java中多线程和线程安全是什么
    这篇文章给大家分享的是有关java中多线程和线程安全是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是进程?电脑中时会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。比如下图中...
    99+
    2023-06-25
  • 聊聊java多线程创建方式及线程安全问题
    什么是线程 线程被称为轻量级进程,是程序执行的最小单位,它是指在程序执行过程中,能够执行代码的一个执行单位。每个程序程序都至少有一个线程,也即是程序本身。 线程的状态 新建(New)...
    99+
    2022-11-12
  • java treemap线程安全问题怎么解决
    要解决Java TreeMap的线程安全问题,有以下几种方法:1. 使用Collections.synchronizedMap()方...
    99+
    2023-10-20
    java
  • Java线程安全问题的解决方案
    目录线程安全问题演示解决线程安全问题1.原子类AtomicInteger2.加锁排队执行2.1 同步锁synchronized2.2 可重入锁ReentrantLock3.线程本地变...
    99+
    2022-11-13
  • java多线程怎么保证线程安全
    Java中有多种方式可以保证线程安全,以下是一些常见的方法:1. 使用synchronized关键字:使用synchronized关...
    99+
    2023-09-13
    java
  • 一文搞懂Java中的线程安全与线程同步
    目录1.为什么需要线程同步线程安全问题2.怎么实现线程同步2.1.使用volatile关键字2.2.使用synchronized关键字1.为什么需要线程同步 什么是线程安全:指在被多...
    99+
    2022-11-13
  • Java多线程编程安全如何退出线程
    小编给大家分享一下Java多线程编程安全如何退出线程,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!线程停止Thread提供了一个stop()方法,但是stop()...
    99+
    2023-05-30
    java
  • java多线程之线程安全(重点,难点)
    线程安全 1. 线程不安全的原因:1.1 抢占式执行1.2 多个线程修改同一个变量1.3 修改操作不是原子的锁(synchronized)1.一个锁对应一个锁对象.2.多个锁对应一个锁对象.2.多个锁对应多个锁对象.4. 找出代码错...
    99+
    2023-08-17
    java jvm 开发语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作