当前位置: 首页 > news >正文

【高级编程】synchronized 解决并发问题 类的线程安全类型

文章目录

    • 并发问题
      • 同步方法
      • 同步代码块
    • 线程安全类型
      • ArrayList
      • Hashtable
      • HashMap
      • Vector

多线程共享数据引发的问题

模拟 “A” “B” “C” 三人抢票,总票数10张,打印抢票情况以及剩余票数。

public class Site implements Runnable {int count = 10; // 总票数int num = 0;    // 已抢票数@Overridepublic void run() {while (true) {if (count <= 0) {break;}count--;num++;System.out.println(Thread.currentThread().getName() + "抢到第" + num + "张票,剩余" + count + "张票!");//休眠  模拟网络延时try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();
}}}}
public static void main(String[] args) {Site site = new Site();Thread th1 = new Thread(site,"A");Thread th2 = new Thread(site,"B");Thread th3 = new Thread(site,"C");th1.start();th2.start();th3.start();
}

问题

  • 不是从第1张票开始

  • 存在多人抢到一张票的情况

  • 有些票号没有被抢到

多个线程操作同一共享资源时,将引发数据不安全问题

并发问题

synchronized 在 Java 中是一种悲观锁(Pessimistic Lock)的形式。悲观锁假设最坏的情况,即认为数据总是会被其他线程修改,因此在处理数据之前就先获取锁。这样可以避免数据冲突,但也可能导致较高的竞争开销。

同步方法

使用 synchronized 修饰的方法控制对类成员变量的访问,synchronized 就是为当前的线程声明一把锁

访问修饰符 synchronized 返回类型 方法名(参数列表){……}

synchronized 访问修饰符 返回类型 方法名(参数列表){……}

使用同步方法的网络购票

public class Site implements Runnable{int count = 10; // 总票数int num = 0;    // 已抢票数@Overridepublic void run() {while(true){if(qg()){ break; }//休眠  模拟网络延时try {Thread.sleep(500); // 休眠半秒} catch (InterruptedException e) {e.printStackTrace();}}}public synchronized boolean qg(){if(count <= 0){ return true; }count--;num++;System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");return false;}}

同步代码块

使用 synchronized 关键字修饰的代码块

synchronized(syncObject){// 需要同步的代码
}
  • syncObject 为需同步的对象,通常为 this
  • 效果与同步方法相同

使用同步代码块的网络购票

public class Site implements Runnable{int count = 10; // 总票数int num = 0;    // 已抢票数@Overridepublic void run() {while(true){//同步synchronized (this){if(count <= 0){ break;}count--;num++;System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");}//休眠  模拟网络延时try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();
}}}}

多个并发线程访问同一资源的同步代码块时

  • 同一时刻只能有一个线程进入同步代码块

  • 当一个线程访问一个同步代码块时,其他同步代码块同样被锁定

  • 当一个线程访问一个同步代码块时,其他线程可以访问该资源的非同步代码

线程安全类型

为达到安全性和效率的平衡,可以根据实际场景来选择合适的类型

方法是否同步效率比较适合场景
线程安全多线程并发共享资源
非线程安全单线程
HashtableHashMap
继承关系实现了 Map 接口,继承 Dictionary实现了 Map 接口,继承 AbstractMap
安全性线程安全,效率较低非线程安全,效率较高
键值键和值都不允许为 null键和值都允许为 null
StringBufferStringBuilder
安全性线程安全非线程安全
适合场景适用于多线程环境中的字符串大量操作适用于单线程环境中的字符串拼接

ArrayList

非线程安全

// 查看 ArrayList 类的 add() 方法定义
public boolean add(E e) {ensureCapacityInternal(size + 1); // 集合扩容,确保能新增数据elementData[size++] = e; // 在新增位置存放数据return true;
}

ArrayList 类的 add() 方法为非同步方法。当多个线程向同一个 ArrayList 对象添加数据时,可能出现数据不一致问题

Hashtable

线程安全

Hashtable<String,String> hashtable = new Hashtable<>();
hashtable.put("","");public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.......
}

HashMap

非线程安全

HashMap:在多线程环境中,可能会导致数据丢失或结构破坏。

HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("","");public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}

Vector

线程安全

Vector vector = new Vector();
vector.add("");public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}
http://www.lryc.cn/news/437230.html

相关文章:

  • Speculative RAG:为知识密集型数据服务的RAG
  • [Go]-抢购类业务方案
  • Android 源码多个Launcher设置默认Launcher
  • 计算机毕业设计 网上体育商城系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • 深度学习中实验、观察与思考的方法与技巧
  • 记一次 FastDFS 存储节点迁移:基于 scp 的实践与经验分享
  • http连接github远程仓库密码问题解决办法
  • LAMP环境下项目部署
  • Visual Studio 2022从外部引入dll导致的问题
  • 大模型从失败中学习 —— 微调大模型以提升Agent性能
  • 10.web应用体系以及windows网络常见操作应用
  • 【数据结构与算法 | 灵神题单 | 前后指针(链表)篇】力扣19, 61,1721
  • 机器学习之实战篇——MNIST手写数字0~9识别(全连接神经网络模型)
  • ICLR2024: 大视觉语言模型中对象幻觉的分析和缓解
  • 数据库系统 第54节 数据库优化器
  • 微服务杂谈
  • 【Pandas操作2】groupby函数、pivot_table函数、数据运算(map和apply)、重复值清洗、异常值清洗、缺失值处理
  • 如何分辨IP地址是否能够正常使用
  • Sqoop 数据迁移
  • 【数据结构】排序算法系列——希尔排序(附源码+图解)
  • c++(继承、模板进阶)
  • 【机器学习】从零开始理解深度学习——揭开神经网络的神秘面纱
  • WebLogic 笔记汇总
  • leetcode:2710. 移除字符串中的尾随零(python3解法)
  • Python GUI入门详解-学习篇
  • QT5实现https的post请求(QNetworkAccessManager、QNetworkRequest和QNetworkReply)
  • vscode 使用git bash,路径分隔符缺少问题
  • F12抓包10:UI自动化 - Elements(元素)定位页面元素
  • android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。
  • SQL入门题