多线程(同步)

2023-11-15

一、为什么要使用线程同步

1、什么是同步

同步就是协同步调,按预定的先后次序进行运行。如:你用完,其它人才能用。“同”字从字面上容易理解为一起

其实不是,“同”字应是指协同、协助、互相配合。

当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。

2、如果不用同步产生的问题

当多个线程同时读写同一份共享资源的时候,有可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到。比如下面不使用同步会产生的问题

  • 举个栗子

    public class Bank {
          /** * 账户余额 */ private int count = 0; /** * 存钱 * * @param money */ public void addMoney(int money) {
          count += money; System.out.println(System.currentTimeMillis() + "存进:" + money); } /** * 取钱 * * @param money */ public void delMoney(int money) {
          if (count - money < 0) {
          System.out.println("余额不足"); return; } count -= money; System.out.println(System.currentTimeMillis() + "取出:" + money); } /** * 查询 */ public void lookMoney() {
          System.out.println("账户余额:" + count); } } 
    // 两个线程 不停的存钱 取钱 public class SyncThreadBankExample { public static void main(String[] args){ final Bank bank=new Bank(); // 存钱线程 Thread tadd=new Thread(() -> { while(true){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } // 存100块到账户 bank.addMoney(100); // 查看余额 bank.lookMoney(); System.out.println("\n"); } }); // 取钱的线程 Thread tsub = new Thread(() -> { while(true){ bank.delMoney(100); bank.lookMoney(); System.out.println("\n"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }); tsub.start(); tadd.start(); } } 
    1564304836893取出:100 账户余额:1200 1564304836893存进:100 账户余额:1200 

3、什么时候使用同步

  1. 多个线程执行的时候需要同步,如果是单线程则不需要同步。

  2. 多个线程在执行的过程中是不是使用同一把锁。

4、常见的同步方案

  1. synchronized(同步)
  2. ReentrantLock (可重入锁)
  3. Atomic( 原子类,效率较高,可用于优化 )
  4. ThreadLocal (线程本地变量)

二、同步(synchronized)

1、说明

synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的。synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,这是synchronized实现同步的基础。

每个进程中访问临界资源的那段代码称为临界区(临界资源是同一时刻一次仅允许一个进程使用的共享资源)

2、锁机制有如下两种特性:

  1. 互斥性:

    即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性

  2. 可见性

    必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。

3、类锁和对象锁

  1. 类锁

    在代码中的方法上加了static和synchronized的锁,或者synchronized(xxx.class)

  2. 对象锁

    在代码中的方法上加了synchronized的锁,或者synchronized(this)的代码段

  3. 注意

    • 类锁和对象锁不会产生竞争,二者的加锁方法不会相互影响。
    • 一个实例对象一把锁,多个实例对象多把锁.多线程解决高并发只能通过一个加锁实例实现

4、根据修饰对象用法分类

  1. 修饰代码块
    • synchronized(this|object) {}
    • synchronized(类.class) {}
  2. 修饰方法
    • 修饰非静态方法
    • 修饰静态方法
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程(同步) 的相关文章

随机推荐

  • 强大的4开关升降压BOB电源 可升可降能大能小

    原文来自公众号 工程师 基于电感器的开关架构电源有3中常见的拓扑结构 分别是BUCK降压电源 BOOST升压电源以及BUCK BOOST负压电源 今天介绍的第4中拓扑 4开关BOB电源 在手机 汽车 嵌入式等领域都有广泛应用 它的基本工作原
  • http响应头connection的作用

    http chenchendefeng iteye com blog 461248 有的网站会在服务器运行一段时间后down掉 有很多原因可能造成这种现象 比如tomcat堆和非堆内存设置不足 程序没能释放内存空间造成内存溢出 或者某些进程
  • 渗透测试信息收集

    信息收集 渗透的本质是信息收集 信息收集分为主动信息收集和被动信息收集 主动信息收集能够收集到更多的信息 但是会产生痕迹 容易被溯源 被动信息收集是信息收集的第一步 通过第三方工具进行收集 不与主机直接交互 需要收集的信息包括 域名 子域名
  • TCP\UDP服务器与客户端

    作业 1 搭建TCP服务器 客户端 2 搭建UDP服务器 客户端 TCP服务器 include
  • 关于Java锁的面试总结

    面试过程中 也被问过几次关于Java中锁的问题 面试官一般是这么问 你了解Java中的锁吗 有几种 都有什么区别 讲一讲 大致可以分为这几点 锁是什么 有什么用 有哪几种锁 锁的区别 一 锁是什么 有什么用 锁主要用来实现资源共享的同步 只
  • Java实战项目(一)---编写聊天室程序

    刚开始学java 参考 java从入门到精通 这本书 学到网络程序设计基础这一章节 尤其与其他计算机进行通信 觉得还挺有意思的 所有深入地试试做一个小程序 聊天室程序 在代码中加入我自己的理解和困惑 希望能和大家一起探讨 每行的代码基本都有
  • [新人向]MySQL和Navicat下载、安装及使用详细教程

    MySQL和Navicat下载和安装及使用详细教程 因为这些软件的安装很多都是纯英文 作为新手安装真的需要摸索好久 包括我自己 所以Pipi酱就把自己的经验分享给大家 MySQL的安装教程 一 下载安装包链接 1 下载MySQL https
  • 广东电信:故障是外力强加导致 警方介入调查

    昨日下午5时50分开始 广东省内电信网络出现故障 省内多个地区均出现网络宽带无法连接 浏览器无法打开网页等现象 消息发布后 不少外省网友跟帖也表示网络塞车 涉及湖北 湖南 广西 海南和上海等省市区 广东本地不少市民在拨打电信 10000 热
  • 第4章(下)基于前馈神经网络完成鸢尾花分类任务

    文章目录 4 5 实践 基于前馈神经网络完成鸢尾花分类 4 5 1 小批量梯度下降法 4 5 1 1 数据分组 4 5 2 数据处理 4 5 2 2 用DataLoader进行封装 4 5 3 模型构建 4 5 4 完善Runner类 4
  • mac 安装打包工具fastlane

    mark ruby gem工具升级相关 查看gem版本 gem version 查看vgem 版本 ruby vgem version ruby版本管理工具更新 gem update system 查看ruby版本 ruby v 查看rub
  • vue3的provide

    provide 和 inject 通常成对一起使用 使一个祖先组件作为其后代组件的依赖注入方 无论这个组件的层级有多深都可以注入成功 只要他们处于同一条组件链上 provide 提供一个值 可以被后代组件注入 inject 注入一个由祖先组
  • fib

    费氏阵列并不是使用递回来解一定不好 事实上单就执行次数上来说 有一个使用递回的演算法可以更快 big o 是以2为底的Logn值 但是要使用到乘法运算 所以实际上要看所使用的机器而定 Procedure FIB N IF n lt 1 RE
  • redis 击穿、穿透、雪崩

    缓存击穿 单个key在缓存中查询不到 转而去查数据库 如果数据量大 或 并发高 则可能会对数据库造成巨大压力 从而导致数据库崩溃 注意 这里的是 单个key 发生高并发 场景 刚好某个时间点 某单个key缓存过期了 恰好这个时间点 针对于这
  • 笔记本重装系统后蓝屏记录

    大白菜制作U盘启动盘 刚好公司有个纯净版的系统iso镜像 然而重装系统的时候手贱勾选了USB3 0的驱动 导致安装后出现蓝屏 原因是驱动与设备不兼容导致 还以为是系统的问题 原先都是安装雨木林风的ghost版本 到没遇到这个问题 今天可把我
  • MySQL笔记(1)安装MySQL5.6

    知识来源 PHP与MySQL程序设计 第四版 yum 安装MySQL 禁用selinux sudo sed i s SELINUX enforcing SELINUX disabled etc selinux config 重启服务器后 查
  • saltstack的配置管理与数据系统

    saltstack的配置管理与数据系统 1 YAML语言 1 1 YAML的基本规则 2 使用SaltStack配置一个apache实例 2 1 在Master上部署sls配置文件并执行 3 使用SaltStack在minion02上配置n
  • 一小时学会js-b站笔记

    Javascript中代理的代码示例 Proxy 代理 const obj name 吴昊 age 18 const container document getElementById const p1 new Proxy obj get
  • 启动roketMq 错误: 找不到或无法加载主类 Files\Java\jdk1.8.0_291\jre\lib\ext

    安装roketMQ出现报错 检查mq的环境变量配置无误 最后锁定到Java环境变量 测试java javac java version都正常 那就蛋疼了 最后一看jdk是安装在Program Files目录下的 问题就出在这里 卸载JDK
  • 在Linux系统里使用Apache搭建Web网站服务器

    使用Apache搭建Web网站服务器 Apache服务 Apache被研发于1995年 是纯开源软件 用于HTTP协议提供web浏览服务 可在Unix Linux Windows上运行 1 配置静态IP vim etc sysconfig
  • 多线程(同步)

    一 为什么要使用线程同步 1 什么是同步 同步就是协同步调 按预定的先后次序进行运行 如 你用完 其它人才能用 同 字从字面上容易理解为一起 其实不是 同 字应是指协同 协助 互相配合 当有一个线程在对内存进行操作时 其他线程都不可以对这个