• 多线程(四)~数据操作的原子性,使用原子性操作AutomicInteger替换非原子性的i++的操作


    这一章,我们要来验证volatile关键字不是原子性的,OK,还是用代码来说话。

    ①.线程类,操作i++ 500次
    1. package com.multiThread.thread;
    2. publicclassNumberThreadimplementsRunnable{
    3. privatevolatileint num =0;
    4. @Override
    5. publicvoid run(){
    6. for(int i =0;i<500;i++){
    7. num++;
    8. }
    9. }
    10. publicint getNum(){
    11. return num;
    12. }
    13. publicvoid setNum(int num){
    14. this.num = num;
    15. }
    16. }
    ②.测试类,创建5个线程同时执行
    1. package com.multiThread.test.automic;
    2. import com.multiThread.thread.NumberThread;
    3. publicclassAutomicTest{
    4. publicstaticvoid main(String[] args){
    5. NumberThread numThread =newNumberThread();
    6. for(int i =0;i<5;i++){
    7. Thread t =newThread(numThread);
    8. t.start();
    9. }
    10. try{
    11. Thread.sleep(1000);
    12. }catch(InterruptedException e){
    13. e.printStackTrace();
    14. }
    15. System.out.println(numThread.getNum());
    16. }
    17. }
    多次运行结果:(正常结果2500居多)
    1. 2500
    2. 2282
    3. 2458
     
    为什么造成这种现象?
    首先我们要知道i++不是原子操作,是线程不安全的,它分为以下3步:
    1.获取i的值
    2.执行i+1的操作
    3.将结果赋值给i
    其次就算变量已经使用volatile关键字来修饰,只能保证读取全局变量num值的时候从主存拿到的是最新的值。
    但是当多个线程同时操作自加的时候,如果之前取到的是同一个值,再自加后得到的值是相同的。
     
    解决的方式如下两种:
    1.可以使用synchronize关键字进行同步操作,这种情况需要把volatile去掉。因为synchronize本身就会操作工作内存和主内存直接的数据同步,此方式不再赘述。
    2.将i++更改为线程安全的原子性操作,使用AtomicInteger替代i++
     
    ①.线程类
    1. package com.multiThread.thread;
    2. import java.util.concurrent.atomic.AtomicInteger;
    3. publicclassNumberThread2implementsRunnable{
    4. privateAtomicInteger num =newAtomicInteger();
    5. @Override
    6. publicvoid run(){
    7. for(int i =0;i<500;i++){
    8. num.incrementAndGet();
    9. }
    10. }
    11. publicAtomicInteger getNum(){
    12. return num;
    13. }
    14. publicvoid setNum(AtomicInteger num){
    15. this.num = num;
    16. }
    17. }
    ②.测试类
    1. package com.multiThread.test.automic;
    2. import com.multiThread.thread.NumberThread;
    3. import com.multiThread.thread.NumberThread2;
    4. publicclassAutomicTest{
    5. publicstaticvoid main(String[] args){
    6. NumberThread2 numThread2 =newNumberThread2();
    7. for(int i =0;i<5;i++){
    8. Thread t =newThread(numThread2);
    9. t.start();
    10. }
    11. try{
    12. Thread.sleep(1000);
    13. }catch(InterruptedException e){
    14. e.printStackTrace();
    15. }
    16. System.out.println(numThread2.getNum());
    17. }
    18. }
    运行结果
    1. 2500
     
     
     
     
     
     
     





  • 相关阅读:
    典型页面布局
    网站表单输入框去除浏览器默认样式
    时间格式问题
    经典算法
    css自动换行
    git pull报“unable to update local ref”解决方案
    MYSQL数据插入和更新的语法
    正则表达式去除连续重复的字符
    linux保存住github的账号和密码
    php动态获取常量
  • 原文地址:https://www.cnblogs.com/douJiangYouTiao888/p/6473807.html
Copyright © 2020-2023  润新知