范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Java锁机制了解一下

  在多线程环境下,程序往往会出现一些线程安全问题,为此,Java提供了一些线程的同步机制来解决安全问题,比如:synchronized锁和Lock锁都能解决线程安全问题。悲观锁和乐观锁
  我们可以将锁大体分为两类:悲观锁乐观锁
  顾名思义,悲观锁总是假设最坏的情况,每次获取数据的时候都认为别的线程会修改,所以每次在拿数据的时候都会上锁,这样其它线程想要修改这个数据的时候都会被阻塞直到获取锁。比如MySQL数据库中的表锁、行锁、读锁、写锁等,Java中的synchronized和ReentrantLock等。
  而乐观锁总是假设最好的情况,每次获取数据的时候都认为别的线程不会修改,所以并不会上锁,但是在修改数据的时候需要判断一下在此期间有没有别的线程修改过数据,如果没有修改过则正常修改,如果修改过则这次修改就是失败的。常见的乐观锁有版本号控制、CAS算法等。悲观锁应用
  案例如下:public class LockDemo {      static int count = 0;      public static void main(String[] args) throws InterruptedException {         List threadList = new ArrayList<>();         for (int i = 0; i < 50; i++) {             Thread thread = new Thread(() -> {                 for (int j = 0; j < 1000; ++j) {                     count++;                 }             });             thread.start();             threadList.add(thread);         }         // 等待所有线程执行完毕         for (Thread thread : threadList) {             thread.join();         }         System.out.println(count);     } }
  在该程序中一共开启了50个线程,并在线程中对共享变量count进行++操作,所以如果不发生线程安全问题,最终的结果应该是50000,但该程序中一定存在线程安全问题,运行结果为:
  48634
  若想解决线程安全问题,可以使用synchronized关键字:public class LockDemo { static int count = 0; public static void main(String[] args) throws InterruptedException { List threadList = new ArrayList<>(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(() -> { // 使用synchronized关键字解决线程安全问题 synchronized (LockDemo.class) { for (int j = 0; j < 1000; ++j) { count++; } } }); thread.start(); threadList.add(thread); } for (Thread thread : threadList) { thread.join(); } System.out.println(count); } }   将修改count变量的操作使用synchronized关键字包裹起来,这样当某个线程在进行++操作时,别的线程是无法同时进行++的,只能等待前一个线程执行完1000次后才能继续执行,这样便能保证最终的结果为50000。   使用ReentrantLock也能够解决线程安全问题:public class LockDemo { static int count = 0; public static void main(String[] args) throws InterruptedException { List threadList = new ArrayList<>(); Lock lock = new ReentrantLock(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(() -> { // 使用ReentrantLock关键字解决线程安全问题 lock.lock(); try { for (int j = 0; j < 1000; ++j) { count++; } } finally { lock.unlock(); } //java学习交流:737251827 进入可领取学习资源及对十年开发经验大佬提问,免费解答! }); thread.start(); threadList.add(thread); } for (Thread thread : threadList) { thread.join(); } System.out.println(count); } }   这两种锁机制都是悲观锁的具体实现,不管其它线程是否会同时修改,它都直接上锁,保证了原子操作。乐观锁应用   由于线程的调度是极其耗费操作系统资源的,所以,我们应该尽量避免线程在不断阻塞和唤醒中切换,由此产生了乐观锁。   在数据库表中,我们往往会设置一个version字段,这就是乐观锁的体现,假设某个数据表的数据内容如下:   +----+------+----------+ ------- +   | id | name | password | version |   +----+------+----------+ ------- +   | 1 | zs | 123456 | 1 |   +----+------+----------+ ------- +   它是如何避免线程安全问题的呢?   假设此时有两个线程A、B想要修改这条数据,它们会执行如下的sql语句:select version from e_user where name = "zs"; update e_user set password = "admin",version = version + 1 where name = "zs" and version = 1;   首先两个线程均查询出zs用户的版本号为1,然后线程A先执行了更新操作,此时将用户的密码修改为了admin,并将版本号加1,接着线程B执行更新操作,此时版本号已经为2了,所以更新肯定是失败的,由此,线程B就失败了,它只能重新去获取版本号再进行更新,这就是乐观锁,我们并没有对程序和数据库进行任何的加锁操作,但它仍然能够保证线程安全。CAS   仍然以最开始做加法的程序为例,在Java中,我们还可以采用一种特殊的方式来实现它:public class LockDemo { static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { List threadList = new ArrayList<>(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(() -> { for (int j = 0; j < 1000; ++j) { // 使用AtomicInteger解决线程安全问题 count.incrementAndGet(); } }); thread.start(); threadList.add(thread); } for (Thread thread : threadList) { thread.join(); } System.out.println(count); } }   为何使用AtomicInteger类就能够解决线程安全问题呢?   我们来查看一下源码:public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }   当count调用incrementAndGet()方法时,实际上调用的是UnSafe类的getAndAddInt()方法:public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }   getAndAddInt()方法中有一个循环,关键的代码就在这里,我们假设线程A此时进入了该方法,此时var1即为AtomicInteger对象(初始值为0),var2的值为12(这是一个内存偏移量,我们可以不用关心),var4的值为1(准备对count进行加1操作)。   首先通过AtomicInteger对象和内存偏移量即可得到主存中的数据值:var5 = this.getIntVolatile(var1, var2);   获取到var5的值为0,然后程序会进行判断:!this.compareAndSwapInt(var1, var2, var5, var5 + var4)   compareAndSwapInt()是一个本地方法,它的作用是比较并交换,即:判断var1的值与主存中取出的var5的值是否相同,此时肯定是相同的,所以会将var5+var4的值赋值给var1,并返回true,对true取反为false,所以循环就结束了,最终方法返回1。   这是一切正常的运行流程,然而当发生并发时,处理情况就不太一样了,假设此时线程A执行到了getAndAddInt()方法:public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }   线程A此时获取到var1的值为0(var1即为共享变量AtomicInteger),当线程A正准备执行下去时,线程B抢先执行了,线程B此时获取到var1的值为0,var5的值为0,比较成功,此时var1的值就变为1;这时候轮到线程A执行了,它获取var5的值为1,此时var1的值不等于var5的值,此次加1操作就会失败,并重新进入循环,此时var1的值已经发生了变化,此时重新获取var5的值也为1,比较成功,所以将var1的值加1变为2,若是在获取var5之前别的线程又修改了主存中var1的值,则本次操作又会失败,程序重新进入循环。   这就是利用自旋的方式来实现一个乐观锁,因为它没有加锁,所以省下了线程调度的资源,但也要避免程序一直自旋的情况发生。手写一个自旋锁public class LockDemo { private AtomicReference atomicReference = new AtomicReference<>(); public void lock() { // 获取当前线程对象 Thread thread = Thread.currentThread(); // 自旋等待 while (!atomicReference.compareAndSet(null, thread)) { } } public void unlock() { // 获取当前线程对象 Thread thread = Thread.currentThread(); atomicReference.compareAndSet(thread, null); } //java学习交流:737251827 进入可领取学习资源及对十年开发经验大佬提问,免费解答! static int count = 0; public static void main(String[] args) throws InterruptedException { LockDemo lockDemo = new LockDemo(); List threadList = new ArrayList<>(); for (int i = 0; i < 50; i++) { Thread thread = new Thread(() -> { lockDemo.lock(); for (int j = 0; j < 1000; j++) { count++; } lockDemo.unlock(); }); thread.start(); threadList.add(thread); } // 等待线程执行完毕 for (Thread thread : threadList) { thread.join(); } System.out.println(count); } }   使用CAS的原理可以轻松地实现一个自旋锁,首先,AtomicReference中的初始值一定为null,所以第一个线程在调用lock()方法后会成功将当前线程的对象放入AtomicReference,此时若是别的线程调用lock()方法,会因为该线程对象与AtomicReference中的对象不同而陷入循环的等待中,直到第一个线程执行完++操作,调用了unlock()方法,该线程才会将AtomicReference值置为null,此时别的线程就可以跳出循环了。   通过CAS机制,我们能够在不添加锁的情况下模拟出加锁的效果,但它的缺点也是显而易见的:循环等待占用CPU资源只能保证一个变量的原子操作会产生ABA问题

赛摩智能2022年第一季度净利493。7万同比增长7。2智能化项目部分在本期完工确认收入挖贝网4月23日,赛摩智能(300466)发布2022年第一季度报告,报告期内公司实现营业收入163,013,074。64元,同比增长35。88归属于上市公司股东的净利润4,9362021年中国数字阅读产业总体规模达415。7亿元中新社北京4月23日电(记者刘育英)4月23日是世界读书日。当日发布的2021年度中国数字阅读报告显示,2021年,中国数字阅读产业总体规模达415。7亿元人民币,增长率达18。2华为北汽合作SUV六月上市!全系1。5T,8万起,造型喜欢吗?北汽全新SUV魔方原定于4月上市,汽车元宇宙从北汽4S店处获悉,魔方上市日期预计将推迟至6月,售价或在812万元。新车定位紧凑级SUV,整车尺寸小于竞品车型欧尚X7PLUS,另外其马云看过的书,你读过吗!万万没想到马云看过这书?在福布斯发布的全球亿万富翁排行榜上,阿里巴巴创始人马云排名第17位。他是中国最富有的人,拥有388亿美元的净资产。在过去的20年里,在马云的领导下,阿里巴巴已经从一家只有几人的小公15级地震有多可怕?能量比8级大地震大316亿倍,地球上能发生吗?如果发生15级地震,地球会发生什么?那将会是非常可怕的场景。山崩地裂不足以形容其可怕。地震带来的破坏地震是怎么形成的呢?形成地震的主要原因是地球板块之间相互挤压碰撞,造成板块边缘以C语言经典100例80题目76题目编写一个函数,输入n为偶数时,调用函数求12141n,当输入n为奇数时,调用函数11131n(利用指针函数)includecstdiodefineRregister指针销量碾压小鹏蔚来,技术直追比亚迪特斯拉,埃安这也太豪横了在这个长袖善舞的时代里,并不缺少低调而又努力的自主新能源汽车品牌,比如今天的主角广汽埃安。它在销量上碾压小鹏蔚来,技术上又直追比亚迪特斯拉,今天我们不妨来看看它凭什么这么豪横?1销取消充电器真环保?苹果晒两年环保成绩单丨iPhone14新配色曝光今天网上曝光了关于iPhone14系列更多细节的CAD渲染图iPhone14Pro相比上代13Pro,边框R角的弧度似乎更加圆润了,这样的设计主要还是用来匹配机身背部更大的相机模组欧美暂停中国邮包服务?联邦快递称消息不实4月23日,网上有消息称欧美多国宣布暂停中国邮政包裹服务。记者从联邦快递中国公司获悉,暂停中国邮包服务的消息不实,恰恰相反,联邦快递准备从4月25日起恢复部分华东地区的进口服务。网华亚智能专注广角摄像头立志做全球最佳华亚智能已经成为集研发生产销售和售后服务为一体的高新技术企业。南方日报记者关铭荣摄明亮的生产车间内,智能机械臂对光学产品进行精加工,工程师在一旁监测着显示器上的指令。专注于精密光学最新5G专利排名华为第1,占全球14,中兴大唐OPPO进入前10一直以来,关于5G技术谁最强,就是网友们最关注的话题之一。而怎么来评价5G技术最强?很多人认为专利是重要标准之一,所以每次全球的权威机构们发布5G专利排行榜时,大家都会特别关注。而
使用指南蓝牙网关怎么供电,怎么上传数据?蓝牙网关就是内部集成为蓝牙WiFi蓝牙WiFi4G等多种无线通信方式的网关产品,多用于数据采集数据传输远程控制和室内定位应用。有很多小伙伴们想了解跟多蓝牙网关的供电和数据上传方式,支持精密单点定位的高精度定位模块介绍SKYLAB精密单点定位指的是利用全球若干地面跟踪站的GPS观测数据计算出的精密卫星轨道和卫星钟差,对单台GPS接收机所采集的相位和伪距观测值进行定位解算。通常,卫星导航系统能够提供10米左右WiFi模块蓝牙模块带您了解数据透传的重要性在SKYLAB众多无线模块的咨询中,有业务纯熟的物联网工程师们直接找数据透传WiFi模块和数据透传蓝牙模块,也有问数据透传是怎么实现的萌新工程师们。本篇SKYLAB小编就以数据透传一文看懂SKYLAB工业级双频定位模块SKG122Y新特性近日,SKYLAB推出了一款工业级标准的双频定位模块SKG122Y,在很大程度上弥补了定位模块的市场空缺,相信已经有很多工程师迫不及待想详细了解一下这一款定位模块了吧。工业级双频多工业级SPI接口WiFi模块WG228助力工业物联网数据传输工业物联网简单来说就是工业领域的物联网技术,物联网架构可分为三层感知层网络层和应用层,主要涵盖了数据的采集传输及分析应用。物联网应用都有一个共同点收集数据并将其发送到服务器或其他系面向高速率传输的双频WiFi模块及无线解决方案数据传输作为物联网应用中的信息支撑,其应用范围已遍布各个领域,无论是在人们日常生活中使用的白色家电等家用电器,还是无人飞行器等消费电子产品,以及各类机器人等工业控制产品等方面,都有第十四届中国商业信息化行业大会首批合作企业名单出炉赋能进化,在变革中赢得先机2021年第十四届中国商业信息化行业大会暨第十四届智慧商业信息化展览会首批合作企业名单地点南昌绿地国际博览中心时间2021年3月2527日同期2021年智普华永道企业如何进行数字化战略转型盒马用快时尚思维做生鲜普华永道企业如何进行数字化战略转型企业推进数字化转型的过程中,业务应用IT架构组织机制建设等工作环环相扣。企业要分清哪是因哪是果,建立多维度的企业数字化成熟度评估体系,用于判断企业第十届商业信息化赋能智慧商业数字化转型研讨会圆满举办随着数字化在零售行业受到越来越高的重视,IT及服务商企业已经看到了未来的希望。虽然眼下还有很多困难,需要面对各种不确定性因素,但是帮助零售企业进行数字化转型的道路一定是光明的。疫情实体零售会员体系构建的实战逻辑与思考为充分深化会员高效运营,日前中国零售CIO俱乐部,智慧零售与餐饮通过组织在线交流,探讨实体零售会员运营逻辑与实战问题。本文围绕信誉楼百货(及旗下各业态)构建会员运营体系(组织架构积零售数字化解决方案及智能设备最新看点日前,在第二十二届中国零售业博览会(CHINASHOP2020)期间,智慧零售与餐饮作为专注于零售业智能化管理和数字化运营的专业媒体,探访了国内智能信息技术展的代表性展商的新技术新