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

网页qq版360优化大师最新版下载

网页qq版,360优化大师最新版下载,物流官网网站,手机电脑同步wordpress线程安全问题的万恶之源就是多线程的抢占式执行所带来的随机性. 有了多线程, 此时抢占式执行下, 代码执行的顺序, 会出现更多的变数, 代码执行顺序的可能性就从一种情况变成了无数种情况. 只要有一种情况使得代码结果不正确, 都是视为bug, 线程不安全. 有线程安全的代码 以下…

线程安全问题的万恶之源就是多线程的抢占式执行所带来的随机性.

有了多线程, 此时抢占式执行下, 代码执行的顺序, 会出现更多的变数, 代码执行顺序的可能性就从一种情况变成了无数种情况. 只要有一种情况使得代码结果不正确, 都是视为bug, 线程不安全.

有线程安全的代码

以下是一个有线程安全的的代码:

class Counter{public int count;public void add(){count++;}
}public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();//搞两个线程, 两个线程分别针对counter 来调用5w次的add方法Thread t1 = new Thread(() -> {for(int i = 0;i < 50000;i++){counter.add();}});Thread t2 = new Thread(() -> {for(int i = 0;i < 50000;i++){counter.add();}});//启动线程t1.start();t2.start();//等待两个线程结束try{t1.join();t2.join();} catch (InterruptedException e){e.printStackTrace();}//打印最终的 count 值System.out.println("count = "+counter.count);}

代码结果:

从代码结果可以知道, 并不是和预期一样, 达到10w次.

为什么会出现这种情况呢?

原因就出现在 "count++" 这里

"++" 操作本质上要分成三步(类似于汇编)

第一步: 先把内存中的值, 读取到CPU的寄存器中 (load)

第二部: 把CPU寄存器里的数值进行 "+1" 运算 (add)

第三步: 把得到的结果写回到内存中 (save)

如果是两个线程并发执行, 此时就相当于两组load add save 进行执行, 此时不同的线程调度顺序就可能会产生一些结果上的差异.(将相当于6个操作, 可能出现的排列次序不同)

这是由于线程之间是随机调度的, 导致此处的调度顺序充满着其他的可能性

脏读

由于两个核心上处理同一个内存上的变量, 如果是按顺序完成自身的任务(load add save)后, 另一个线程在开始自增, 那么结果肯定是10w次, 但是由于随机调度, 就会出现一个线程自增后, 还没有保存, 而另一个线程已经读取的情况, 就会导致内存上只++1次, 没有按预期一样++2次.

线程安全问题的主要原因

线程安全问题的主要原因:

1. [根本原因] 抢占式执行, 随即调度,

2. 代码结构: 多个线程同时修改同一个变量

    一个线程修改一个变量不会出现安全问题

    多个线程读取同一个变量不会出现安全问题(例如:String是不可变对象, 天然是线程安全的)

    多个线程修改多个不同的变量不会出现安全问题

3.原子性:  如果修改操作是非原子的, 就会容易出现线程安全问题

    原子性: 比如汇编中的一条指令,或者说几条指令互不影响

    针对线程安全问题的解决, 最主要的手段就是从原子性入手, 把非原子的操作, 变为原子的

4. 内存可见性: 如果一个线程读, 一个线程修改 也会出现安全问题

5. 指令重排序: 编译器主动调整你的代码

线程安全问题的解决----Synchronized

//synchronize 是一个关键字, 表示加锁
synchronized public void add(){count++;
}

加了synchronized之后, 进入方法就会加锁, 出了方法就会解锁, 如果两个线程同时尝试加锁, 此时一个能获取锁成果, 另一个只能阻塞等待(BLOCKED) 一直阻塞到线程释放锁(解锁), 当前线程才能加锁成功.

加锁, 就是保证原子性, 加锁的本质是把并行, 变成了串行

加锁之后, 代码结果就变成了10w次

synchronized关键字----监视器monitor lock

synchronized 使用方法

1.修饰方法

  1) 修饰普通方法; 锁对象就是this

public synchronized void add(){count++;
}

直接把synchronized 修饰到方法上了, 此时相当于对 this 加锁.

Thread t1 = new Thread(() -> {for(int i = 0;i < 50000;i++){counter.add();}
});Thread t2 = new Thread(() -> {for(int i = 0;i < 50000;i++){counter.add();}
});

        t1 执行 add 就加上锁了, 针对count这个对象加上锁了, t2 执行 add 的时候, 也尝试对counter加锁, 但是由于counter 已经被 t1 给占用了, 因此这里的加锁操作就会阻塞.

  2)修饰静态方法: 锁对象就是类对象(Counter,class)

     与1) 同理

2.修饰代码块

显式/手动指定锁对象

public void add(){synchronized (this){count++;}
}

  "( )" 内可以指定任意想指定的对象, 不一定非是 this, 进了代码块就加锁, 出了代码块就解锁

synchronized 的特性

1) 互斥

  进入 synchronized 修饰的代码块, 相当于 加锁

  推出synchronized 修饰的代码块, 相当于解锁

加锁

如果两个线程针对同一个对象进行加锁, 就会出现锁竞争/锁冲突, 一个线程能够获取到锁(先到先得)另一个线程阻塞等待, 等待到上一个线程解锁, 它才能获取锁成功

如果两个线程针对不同对象加锁, 此时不会发生锁竞争/锁冲突. 这俩线程都能获取到各自的锁, 不会阻塞等待了.

2) 可重入

synchronized 同步块对同一条线程来说是可重入的, 不会出现自己把自己锁死的问题.

Java标准库中的线程安全类

 

Java标准库中很多都是不是线程安全的. 例如以上, 这些类可能会涉及到多线程修改共享数据, 有没有任何加锁措施

还有一些是线程安全的, 使用了一些锁机制来控制

还有的虽然没加索, 但是不涉及"修改", 仍然是线程安全的-----String

http://www.dtcms.com/wzjs/13738.html

相关文章:

  • 软件外包公司哪个好深圳市企业网站seo
  • dw如何用表格来做网站长沙靠谱seo优化
  • 个人网站怎么备案可以做哪些整合营销策略
  • 铜川市新区建设局网站竞价托管就选微竞价
  • 网站建设公司名龙斗seo博客
  • 任丘哪里做网站网站优化资源
  • 5118网站怎么做的百度seo规则
  • 做翻译兼职的网站网络营销是指什么
  • 长沙创意网站建设seo教程论坛
  • 可以做app的网站百度识图搜索图片来源
  • 成都网站制作培训四川seo排名
  • 网站的首页设计方案网络推广怎么做效果好
  • 巴拉巴拉童装在哪几个网站做直销关键词代发包收录
  • 加盟网站需要怎么做广州关键词优化外包
  • 企业发布招聘信息免费的网站微信客户管理
  • 贵阳做网站方舟网络老域名
  • 网站怎么做外链百度竞价排名展示方式
  • 做百度收录的网站哔哩哔哩b站在线看免费
  • 重庆网站建设哪家公司那家好查询网站注册信息
  • 新竹网站青岛seo全网营销
  • 做的网站一定要收录么淘宝seo搜索优化工具
  • 达浒镇网站建设公司什么是百度快照
  • 网站制作项目如何推广我的网站
  • 网站制作中需要注意的地方温州云优化seo
  • 昆山有做网站的公司吗网络推广公司怎么找客户
  • 网站防复制衡阳seo优化首选
  • 网站建设在哪里seo是如何做优化的
  • 微信属于营销型网站产品品牌策划方案
  • 龙华个人网站建设搜索引擎调价工具哪个好
  • 许昌做网站优化百度一下下载安装