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

网站上的动图都怎么做的新城疫最快解决的办法

网站上的动图都怎么做的,新城疫最快解决的办法,部分网站建设管理不规范,如何用wordpress快速建站概念compare and swap#xff0c;解决多线程并行情况下使用锁造成性能损耗的一种机制#xff0c;CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配#xff0c;那么处理器会自动将该位置值更新为新值。否则#xff0c;处理器…概念compare and swap解决多线程并行情况下使用锁造成性能损耗的一种机制CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配那么处理器会自动将该位置值更新为新值。否则处理器不做任何操作。无论哪种情况它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A如果包含该值则将B放到这个位置否则不要更改该位置只告诉我这个位置现在的值即可。简单点来说就是修改之前先做一下对比校验数据是否被其他线程修改过如果修改过了那么将内存中新的值取出在与内存中的进行对比直到相等然后再做修改。假如我们要对变量num做累加操作num初始值0。1.cpu前往内存取出num2.判断内存中的num是否被修改3.做1操作4.将修改后的值写入内存中这时候可能会有疑问了判断、自加、写回内存难道不会发生线程安全问题吗既然cas能成为并发编程中安全问题的解决这那么这个问题肯定是不会发生的为什么呢因为判断、自加、写回内存这是一个由硬件保证的原子操作硬件是如何保证原子性的请先看下面这个例子需求使用三个线程分别对某个成员变量累加10W打印累加结果。我们使用两种方法完成此需求。1.正常累加(既不加锁也不使用原子类)。1.使用synchronized。2.使用原子类(Atomic)。实现1.正常累加(既不加锁也不使用原子类)。这种方式没有什么说的直接上代码package com.ymy.test;public class CASTest { private static long count 0; /** * 累加10w */ private static void add(){ for (int i 0; i 100000; i){ count1; } } public static void main(String[] args) throws InterruptedException { //开启三个线程 t1 t2 t3 Thread t1 new Thread(() -{ add(); }); Thread t2 new Thread(() -{ add(); }); Thread t3 new Thread(() -{ add(); }); long starTime System.currentTimeMillis(); //启动三个线程 t1.start(); t2.start(); t3.start(); //让线程同步 t1.join(); t2.join(); t3.join(); long endTime System.currentTimeMillis(); System.out.println(累加完成countcount); System.out.println(耗时(endTime - starTime) ms); }}执行结果很明显三个线程累加由于cpu缓存的存在导致结果远远小于30w这个也是我们预期到的所以才会出现后面两种解决方案。2.使用synchronized使用synchronized时需要注意需求要求我们三个线程分别累加10W所以synchronized锁定的内容就非常重要了要么直接锁定类要么三个线程使用同一把锁关于synchronized的介绍以及锁定内容请参考java并发编程之synchronized第一种直接锁定类我这里采用锁定静态方法。我们来改动一下代码将add方法加上synchronized关键字即可由于add方法已经时静态方法了所以现在锁定的时整个CASTest类。 /** * 累加10w */ private static synchronized void add(){ for (int i 0; i 100000; i){ count1; } }运行结果第一次第二次第三次这里就有意思了加了锁的运行时间居然比不加锁的运行时间还少是不是觉得有点不可思议了其实这个也不难理解这里就要牵扯到cpu缓存以及缓存与内存的回写机制了感兴趣的小伙伴可以自行百度今天的重点不在这里。第二种三个线程使用同一把锁改造代码去掉add方法的synchronized关键字将synchronized写在add方法内新建一把钥匙(成员变量lock)让三个累加都累加操作使用这把钥匙代码如下package com.ymy.test;public class CASTest { private static long count 0; private static final String lock lock; /** * 累加10w */ private static void add() { synchronized(lock){ for (int i 0; i 100000; i) { count 1; } } } public static void main(String[] args) throws InterruptedException { //开启三个线程 t1 t2 t3 Thread t1 new Thread(() - { add(); }); Thread t2 new Thread(() - { add(); }); Thread t3 new Thread(() - { add(); }); long starTime System.currentTimeMillis(); //启动三个线程 t1.start(); t2.start(); t3.start(); //让线程同步 t1.join(); t2.join(); t3.join(); long endTime System.currentTimeMillis(); System.out.println(累加完成count count); System.out.println(耗时 (endTime - starTime) ms); }} 结果如下这两种加锁方式都能保证线程的安全但是这里你需要注意一点如果是在方法上加synchronized而不加static关键字的话必须要保证多个线程共用这一个对象否者加锁无效。原子类原子类工具有很多我们举例的累加操作只用到其中的一种我们一起看看java提供的原子工具有哪些工具类还是很丰富的我们结合需求来讲解一下其中的一种我们使用AtomicLong。AtomicLong提供了两个构造函数value原子操作的初始值调用无参构造value0调用有参构造value指定值其中value还是被volatile 关键字修饰volatile可以保证变量的可见性什么叫可见性可见性有一条很重要的规则Happens-Before 规则意思前面一个操作的结果对后续操作是可见的线程1对变量A的修改其他线程立马可以看到具体请自行百度。我们接着来看累加的需求AtomicLong提供了一个incrementAndGet()源码如下 /** * Atomically increments by one the current value. * * return the updated value */ public final long incrementAndGet() { return unsafe.getAndAddLong(this, valueOffset, 1L) 1L; } Atomically increments by one the current value 原子的增加一个当前值。好了我们现在试着将互斥锁修改成原子类工具改造代码1.实例化一个Long类型的原子类工具2.再for循环中使用incrementAndGet()方法进行累加操作。改造后的代码package com.ymy.test;import java.util.concurrent.atomic.AtomicLong;public class CASTest {// private static long count 0; private static final String lock lock; private static AtomicLong atomicLong new AtomicLong(); /** * 累加10w */ private static void add() { for (int i 0; i 100000; i) { atomicLong.incrementAndGet(); } } public static void main(String[] args) throws InterruptedException { //开启三个线程 t1 t2 t3 Thread t1 new Thread(() - { add(); }); Thread t2 new Thread(() - { add(); }); Thread t3 new Thread(() - { add(); }); long starTime System.currentTimeMillis(); //启动三个线程 t1.start(); t2.start(); t3.start(); //让线程同步 t1.join(); t2.join(); t3.join(); long endTime System.currentTimeMillis(); //System.out.println(累加完成count count); System.out.println(累加完成count atomicLong); System.out.println(耗时 (endTime - starTime) ms); }}结果可以得到累加的结果也是30w但时间却比互斥锁要久这是为什么呢我们一起来解剖一下源码。AtomicLong incrementAndGet()源码解析/** * Atomically increments by one the current value. * * return the updated value */ public final long incrementAndGet() { return unsafe.getAndAddLong(this, valueOffset, 1L) 1L; } public final long getAndAddLong(Object var1, long var2, long var4) { long var6; do { var6 this.getLongVolatile(var1, var2); } while(!this.compareAndSwapLong(var1, var2, var6, var6 var4)); return var6; }我们来看看getAndAddLong方法发现内部使用了一个 do while 循环我们看看循环的条件是什么public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);这是循环条件的源码不知道你们发现没有一个关键字native表示java代码已经走完了这里需要调用C/C代码这里调用的时C代码在这里就要解释一下为什么原子类的比较和赋值是线程安全的那是因为c代码中是有加锁的不知道你们是否了解过内存与cpu的消息总线制c就是再消息总线中加了lock保证了互斥性所以对比和赋值是一个原子操作线程安全的。Unsafe这个类可以为原子工具类提供硬件级别的原子性虽然我们java中使用的这些原子工具类虽然都是无锁的但是我们无需考虑他的多线程安全问题。为什么原子类比互斥锁的效率低好了现在来思考一下为什么原子工具类的效率会比互斥锁低明明没有加锁反而比加了锁慢这是不是有点不合常理其实这很符合常理我们一起来分析一波CAS(Compare and Swap)重在比较我们看源码的时候发现有一个 do while循环这个循环的作用是什么呢1.判断期望值是否和内存中的值一致2.如果不一致获取内存中最新的值(var6)此时期望值就等于了var6使用改期望值继续与内存中的值做对比直到发现期望值和内存中的值一致1之后返回结果。这里有一个问题不知道你们发现没有就是这个循环问题1.我们假设线程1最先访问内存中的num值0加载到cpu中2.还没有做累加操作cpu执行了线程切换操作3.线程2得到了使用权线程2也去内存中加载num0累加之后将结果返回到了内存中4.线程切回线程1接着上面的操作要和内存中的num进行对比期望值0内存num1法向对比不上从新获取内存中的num1加载到线程1所在的cpu中5.此时线程又切换了这次切换了线程36.线程3从内存中加载num1到线程3所在的cpu中之后拿着期望值1与内存中的num1做对比发现值并没有被修改此时累加结果之后写回内存7.线程1拿到使用权8.线程1期望值1与内存num2做对比发现又不相同此时又需要将内存中的新num3加载到线程1所在的cpu中然后拿着期望值2与内存num2做对比发现相同累加将结果写回内存。这是再多线程下的一种情况我们发现线程1做了两次对比而真正的程序循环对比的次数肯定会比我们分析的多互斥锁三个线程累加10w只需要累加30万次即可而原子类工具需要累加30万次并且循环很多次可能几千次也可能几十万次所以再内存中累加操作互斥锁会比原子类效率高因为内存的执行效率高会导致一个对比执行很多循环我们称这个循环叫自旋。是不是所有情况下都是互斥锁要快呢肯定不是的如果操作的数据再磁盘中或者操作数据量太多时原子类就会比互斥锁的性能高很多这很好理解就像内存中单线程比多线程效率会更高(一般情况)。CAS的ABA问题ABA是什么我们来举个例子变量a初始值0被线程1获取a0切换到线程2获取a0并且将a修改为1写回内存切换到线程3再内存中获取数据a1将数据修改为0然后写回内存切换到线程1这时候线程1发现内存中的值还是0线程1认为内存中a没有被修改这时候线程1将a的值修改为1写回内存。我们来分析一下这波操作会不会有风险从表面上看好像没什么问题累加或者值修改的时候问题不大觉得这个ABA没有什么风险如果你这样认为那就大错特错了我举个例子用户A用网上银行给用户B转钱同时用户C也在给用户A转钱我们假设用户A账户余额100元用户A要给用户B转100元用户C要给用户A转100元用户A转给用户B、用户C转给用户A同时发生但由于用户A的网络不好用户A点了一下之后没有反应接着又点了一下这时候就会发送两条用户A给用户B转100元的请求。我们假设线程1用户A第一次转用户B100元线程2用户A第二次转用户B100元线程3用户C转用户A100元。线程1执行的时候获取用户A的余额100元此时切换到了线程2也获取到了用户A的余额100元线程2做了扣钱操作(update money-100 where money100)100是我们刚查出来的扣完之后余额应该变成了0元切换到线程3用户C转给用户A100元此时用户A的账户又变成了100元切换到线程1执行扣钱操作(update money-100 where money100)本来是应该扣钱失败的由于用户C给用户A转了100元导致用户A的余额又变成了100元所以线程1也扣钱成功了。这是不是很恐怖所以在开发的时候ABA问题是否需要注意还请分析好应用场景像之前说的这个ABA问题数据库层面我们可以加版本号(版本号累加)就能解决程序中原子类也给我们提供了解决方案AtomicStampedReference感兴趣的小伙伴可以研究一下。其实思路和版本号类似比较的时候不仅需要比较期望值还要对比版本号都相同的情况下才会做修改。
http://www.zqtcl.cn/news/297342/

相关文章:

  • 韩国食品网站设计欣赏深圳最新新闻事件头条
  • 免费的源码网站有哪些ui界面设计总结心得
  • 那个网站可以做视频app制作北京私人做网站
  • 西安市网站制作公司外贸网站建设步骤
  • 学做网站是什么专业广州建站外包公司历史长
  • 网站必备功能桂林网站建
  • 网站导航栏特效网站地图后台可以做吗
  • 站长工具亚洲高清个人网站建设研究意义
  • 网站制作哪家最好数商云怎么样
  • 做棋牌网站违法嘛免费下载百度
  • 兰州营销型网站建设直播app怎么开发
  • 生成拼贴的网站小程序源码之家
  • 想搭建网站学什么长春市建设局网站
  • 深圳做三网合一网站云主机玩游戏
  • 网站打开慢网站制作多少钱?
  • 网站制作多少钱一个月做教育培训应该注册什么公司
  • 网站价格套餐自己网站上做淘宝搜索引擎
  • 个人博客网站的设计与实现百度信息流投放
  • 廊坊网站关键字优化企业网站系统建设
  • 建设一个网站主要受哪些因素的影响php网站后台教程
  • 做购物网站学什么技术go 网站开发
  • 第一个做电子商务的网站工信部网站 备案
  • 一个完整的网站建设花都有沒有网站建设的
  • 哪个网站有适合小学生做的题目建站工具模板
  • 做家教网站赚钱么网站建设算行政工作吗
  • 网站建设seo网络推广专业的营销团队哪里找
  • 能用的网站关于申请开通网站建设的请示
  • 蓬莱网站建设哪家专业怎么样模仿网站
  • 网站建设有什么好处如何查看网站开发源码
  • 惠州做棋牌网站建设哪家好老域名新网站