JAVA 中 atomic 原子类解决线程同步问题

本贴最后更新于 1582 天前,其中的信息可能已经物是人非

第一篇文章

优化前

问题描述:
有二十个线程,前十个线程,每个线程分别对共享变量进行加 1 操作,循环 10 次
后十个线程,每个线程对共享变量进行减 1 操作,循环 10 次
每个线程操作后,输出共享变量的值

直接代码:

package com.yhm.testSpringMvc.Thread;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicClassTestBefore {


    private static Integer integer = new Integer(100);

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new yhmDecrementClass()).start();
            new Thread(new yhmIncrementClass()).start();
        }

    }

    static class yhmIncrementClass implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "," + integer++);
            }


        }
    }

    static class yhmDecrementClass implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "," + integer--);
            }

        }
    }
}

输出结果:

D:\JAVA\jdk8_64\bin\java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:59643,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath "D:\JAVA\jdk8_64\jre\lib\charsets.jar;D:\JAVA\jdk8_64\jre\lib\deploy.jar;D:\JAVA\jdk8_64\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk8_64\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk8_64\jre\lib\ext\dnsns.jar;D:\JAVA\jdk8_64\jre\lib\ext\jaccess.jar;D:\JAVA\jdk8_64\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk8_64\jre\lib\ext\localedata.jar;D:\JAVA\jdk8_64\jre\lib\ext\nashorn.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunec.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk8_64\jre\lib\ext\zipfs.jar;D:\JAVA\jdk8_64\jre\lib\javaws.jar;D:\JAVA\jdk8_64\jre\lib\jce.jar;D:\JAVA\jdk8_64\jre\lib\jfr.jar;D:\JAVA\jdk8_64\jre\lib\jfxswt.jar;D:\JAVA\jdk8_64\jre\lib\jsse.jar;D:\JAVA\jdk8_64\jre\lib\management-agent.jar;D:\JAVA\jdk8_64\jre\lib\plugin.jar;D:\JAVA\jdk8_64\jre\lib\resources.jar;D:\JAVA\jdk8_64\jre\lib\rt.jar;D:\ideaPros\codeGitee\ACM\target\classes;D:\repo\junit\junit\4.12\junit-4.12.jar;D:\repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\repo\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar;D:\repo\org\springframework\spring-core\4.2.5.RELEASE\spring-core-4.2.5.RELEASE.jar;D:\repo\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\repo\org\springframework\spring-beans\4.2.5.RELEASE\spring-beans-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-context\4.2.5.RELEASE\spring-context-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-aop\4.2.5.RELEASE\spring-aop-4.2.5.RELEASE.jar;D:\repo\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\repo\org\springframework\spring-expression\4.2.5.RELEASE\spring-expression-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-tx\4.2.5.RELEASE\spring-tx-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-web\4.2.5.RELEASE\spring-web-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-webmvc\4.2.5.RELEASE\spring-webmvc-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-test\4.2.5.RELEASE\spring-test-4.2.5.RELEASE.jar;D:\repo\org\slf4j\slf4j-log4j12\1.6.6\slf4j-log4j12-1.6.6.jar;D:\repo\org\slf4j\slf4j-api\1.6.6\slf4j-api-1.6.6.jar;D:\repo\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\repo\cglib\cglib-nodep\3.2.2\cglib-nodep-3.2.2.jar;D:\repo\org\aspectj\aspectjweaver\1.7.4\aspectjweaver-1.7.4.jar;D:\repo\com\alibaba\dubbo\2.5.3\dubbo-2.5.3.jar;D:\repo\org\springframework\spring\2.5.6.SEC03\spring-2.5.6.SEC03.jar;D:\repo\org\javassist\javassist\3.15.0-GA\javassist-3.15.0-GA.jar;D:\repo\org\jboss\netty\netty\3.2.5.Final\netty-3.2.5.Final.jar;D:\chengxu\intelliJIDEA\IntelliJ IDEA 2017.3.5\lib\idea_rt.jar" com.yhm.testSpringMvc.Thread.AtomicClassTestBefore
Connected to the target VM, address: '127.0.0.1:59643', transport: 'socket'
Thread-0,100
Thread-0,99
Thread-0,98
Thread-0,97
Thread-0,96
Thread-0,95
Thread-0,94
Thread-0,93
Thread-0,92
Thread-0,91
Thread-2,91
Thread-2,89
Thread-2,88
Thread-2,87
Thread-4,90
Thread-4,85
Thread-3,90
Thread-3,83
Thread-3,84
Thread-1,90
Thread-3,85
Thread-5,84
Thread-4,84
Thread-11,89
Thread-11,89
Thread-9,90
Thread-2,85
Thread-10,92
Thread-10,90
Thread-10,89
Thread-10,88
Thread-6,86
Thread-15,86
Thread-15,86
Thread-15,87
Thread-10,87
Thread-10,89
Thread-10,87
Thread-10,86
Thread-10,85
Thread-10,85
Thread-14,91
Thread-13,91
Thread-13,83
Thread-13,84
Thread-13,85
Thread-2,92
Thread-2,87
Thread-2,86
Thread-2,85
Thread-2,84
Thread-9,91
Thread-11,90
Thread-12,91
Thread-12,85
Thread-12,84
Thread-12,83
Thread-12,82
Thread-4,90
Thread-5,88
Thread-8,89
Thread-8,80
Thread-8,79
Thread-8,78
Thread-8,77
Thread-8,76
Thread-3,88
Thread-3,74
Thread-3,75
Thread-3,76
Thread-3,77
Thread-3,78
Thread-7,87
Thread-1,86
Thread-7,79
Thread-7,81
Thread-7,82
Thread-7,83
Thread-7,84
Thread-7,85
Thread-7,86
Thread-7,87
Thread-7,88
Thread-8,75
Thread-8,89
Thread-5,79
Thread-4,80
Thread-12,81
Thread-12,87
Thread-12,86
Thread-12,85
Thread-12,84
Thread-11,84
Thread-9,83
Thread-13,86
Thread-14,84
Thread-19,84
Thread-18,88
Thread-18,86
Thread-18,85
Thread-18,84
Thread-18,83
Thread-18,82
Thread-18,81
Thread-18,80
Thread-18,79
Thread-18,78
Thread-17,88
Thread-17,77
Thread-17,78
Thread-15,87
Thread-15,79
Thread-16,88
Thread-6,87
Thread-6,80
Thread-16,81
Thread-15,80
Thread-15,77
Thread-15,78
Thread-15,79
Thread-15,80
Thread-17,79
Thread-19,85
Thread-14,86
Thread-13,85
Thread-9,84
Thread-11,83
Thread-11,84
Thread-11,85
Thread-11,86
Thread-11,87
Thread-11,88
Thread-4,88
Thread-4,89
Thread-4,88
Thread-4,87
Thread-4,86
Thread-5,87
Thread-8,88
Thread-1,80
Thread-8,86
Thread-5,85
Thread-9,83
Thread-9,87
Thread-9,88
Thread-9,89
Thread-9,90
Thread-13,82
Thread-13,92
Thread-14,83
Thread-14,94
Thread-14,93
Thread-19,82
Thread-19,91
Thread-19,92
Thread-19,93
Thread-19,94
Thread-19,95
Thread-19,96
Thread-19,97
Thread-17,81
Thread-17,98
Thread-16,78
Thread-16,100
Thread-16,99
Thread-16,98
Thread-16,97
Thread-16,96
Thread-16,95
Thread-16,94
Thread-6,79
Thread-17,99
Thread-14,92
Thread-14,93
Thread-14,92
Thread-14,91
Thread-13,93
Thread-13,90
Thread-9,91
Thread-5,86
Thread-1,85
Thread-1,92
Thread-1,93
Thread-1,94
Thread-1,95
Thread-5,91
Thread-17,92
Thread-6,93
Thread-17,98
Thread-17,98
Thread-5,97
Thread-5,99
Thread-5,100
Thread-1,96
Thread-6,99
Thread-6,102
Thread-6,101
Thread-6,100
Thread-6,99
Thread-1,101
Disconnected from the target VM, address: '127.0.0.1:59643', transport: 'socket'

Process finished with exit code 0

从结果可以看到,最后输出的结果并非 100(共享变量初始值 100)

原因分析:
JAVA 中每个线程对共享变量的操作并非同步进行,为了提升线程的运行速度,对每个线程都有单独的内存分配,即共享变量只有一个,但是每个线程复制了一份到自己的内存区域内。A 线程对共享变量的操作,实际上是对自己单独内存区域内变量的操作,操作完成后并不会马上改变共享变量的值,可以说各自在干着自己线程的事情。

解决办法:需要线程同步,每个线程对共享变量的操作应该马上生效!

优化后

package com.yhm.testSpringMvc.Thread;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicClassTest {


    private static AtomicInteger atomicInteger = new AtomicInteger(100);

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new yhmDecrementClass()).start();
            new Thread(new yhmIncrementClass()).start();
        }

    }

    static class yhmIncrementClass implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "," + atomicInteger.decrementAndGet());
            }


        }
    }

    static class yhmDecrementClass implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "," + atomicInteger.incrementAndGet());
            }

        }
    }
}

输出结果:

D:\JAVA\jdk8_64\bin\java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:60088,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath "D:\JAVA\jdk8_64\jre\lib\charsets.jar;D:\JAVA\jdk8_64\jre\lib\deploy.jar;D:\JAVA\jdk8_64\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk8_64\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk8_64\jre\lib\ext\dnsns.jar;D:\JAVA\jdk8_64\jre\lib\ext\jaccess.jar;D:\JAVA\jdk8_64\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk8_64\jre\lib\ext\localedata.jar;D:\JAVA\jdk8_64\jre\lib\ext\nashorn.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunec.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk8_64\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk8_64\jre\lib\ext\zipfs.jar;D:\JAVA\jdk8_64\jre\lib\javaws.jar;D:\JAVA\jdk8_64\jre\lib\jce.jar;D:\JAVA\jdk8_64\jre\lib\jfr.jar;D:\JAVA\jdk8_64\jre\lib\jfxswt.jar;D:\JAVA\jdk8_64\jre\lib\jsse.jar;D:\JAVA\jdk8_64\jre\lib\management-agent.jar;D:\JAVA\jdk8_64\jre\lib\plugin.jar;D:\JAVA\jdk8_64\jre\lib\resources.jar;D:\JAVA\jdk8_64\jre\lib\rt.jar;D:\ideaPros\codeGitee\ACM\target\classes;D:\repo\junit\junit\4.12\junit-4.12.jar;D:\repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\repo\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar;D:\repo\org\springframework\spring-core\4.2.5.RELEASE\spring-core-4.2.5.RELEASE.jar;D:\repo\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\repo\org\springframework\spring-beans\4.2.5.RELEASE\spring-beans-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-context\4.2.5.RELEASE\spring-context-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-aop\4.2.5.RELEASE\spring-aop-4.2.5.RELEASE.jar;D:\repo\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\repo\org\springframework\spring-expression\4.2.5.RELEASE\spring-expression-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-tx\4.2.5.RELEASE\spring-tx-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-web\4.2.5.RELEASE\spring-web-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-webmvc\4.2.5.RELEASE\spring-webmvc-4.2.5.RELEASE.jar;D:\repo\org\springframework\spring-test\4.2.5.RELEASE\spring-test-4.2.5.RELEASE.jar;D:\repo\org\slf4j\slf4j-log4j12\1.6.6\slf4j-log4j12-1.6.6.jar;D:\repo\org\slf4j\slf4j-api\1.6.6\slf4j-api-1.6.6.jar;D:\repo\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\repo\cglib\cglib-nodep\3.2.2\cglib-nodep-3.2.2.jar;D:\repo\org\aspectj\aspectjweaver\1.7.4\aspectjweaver-1.7.4.jar;D:\repo\com\alibaba\dubbo\2.5.3\dubbo-2.5.3.jar;D:\repo\org\springframework\spring\2.5.6.SEC03\spring-2.5.6.SEC03.jar;D:\repo\org\javassist\javassist\3.15.0-GA\javassist-3.15.0-GA.jar;D:\repo\org\jboss\netty\netty\3.2.5.Final\netty-3.2.5.Final.jar;D:\chengxu\intelliJIDEA\IntelliJ IDEA 2017.3.5\lib\idea_rt.jar" com.yhm.testSpringMvc.Thread.AtomicClassTest
Connected to the target VM, address: '127.0.0.1:60088', transport: 'socket'
Thread-0,101
Thread-0,102
Thread-0,103
Thread-0,104
Thread-0,105
Thread-0,106
Thread-0,107
Thread-0,108
Thread-0,109
Thread-0,110
Thread-1,109
Thread-2,110
Thread-3,108
Thread-3,108
Thread-3,108
Thread-1,109
Thread-6,107
Thread-3,106
Thread-5,107
Thread-4,109
Thread-4,105
Thread-4,107
Thread-4,108
Thread-4,108
Thread-4,109
Thread-4,111
Thread-2,109
Thread-11,111
Thread-11,111
Thread-11,111
Thread-11,110
Thread-11,109
Thread-2,112
Thread-2,109
Thread-4,112
Thread-4,110
Thread-10,110
Thread-9,107
Thread-9,111
Thread-9,110
Thread-9,110
Thread-9,108
Thread-9,107
Thread-9,106
Thread-9,105
Thread-9,104
Thread-9,103
Thread-8,106
Thread-8,104
Thread-8,105
Thread-8,106
Thread-8,107
Thread-8,108
Thread-8,109
Thread-8,110
Thread-8,111
Thread-8,112
Thread-5,104
Thread-3,105
Thread-7,106
Thread-6,107
Thread-6,110
Thread-6,111
Thread-1,106
Thread-6,112
Thread-7,109
Thread-3,110
Thread-3,110
Thread-5,111
Thread-19,109
Thread-18,111
Thread-17,112
Thread-17,107
Thread-17,106
Thread-10,113
Thread-16,112
Thread-16,107
Thread-16,108
Thread-16,109
Thread-16,110
Thread-16,111
Thread-16,112
Thread-16,113
Thread-16,114
Thread-16,115
Thread-4,111
Thread-2,109
Thread-2,116
Thread-15,108
Thread-14,108
Thread-11,107
Thread-11,116
Thread-13,108
Thread-12,112
Thread-12,115
Thread-12,116
Thread-12,117
Thread-12,118
Thread-12,119
Thread-12,120
Thread-12,121
Thread-12,122
Thread-12,123
Thread-13,114
Thread-13,122
Thread-13,121
Thread-13,120
Thread-13,119
Thread-13,118
Thread-11,115
Thread-14,117
Thread-15,116
Thread-2,117
Thread-2,117
Thread-10,106
Thread-17,105
Thread-18,108
Thread-18,119
Thread-18,120
Thread-18,121
Thread-18,122
Thread-18,123
Thread-18,124
Thread-18,125
Thread-19,107
Thread-5,108
Thread-5,124
Thread-5,123
Thread-5,122
Thread-5,121
Thread-5,120
Thread-5,119
Thread-3,109
Thread-3,118
Thread-7,111
Thread-6,112
Thread-6,117
Thread-6,118
Thread-6,119
Thread-6,120
Thread-1,111
Thread-7,116
Thread-3,117
Thread-19,125
Thread-19,117
Thread-19,116
Thread-19,115
Thread-19,114
Thread-19,113
Thread-19,112
Thread-19,111
Thread-18,126
Thread-17,118
Thread-17,110
Thread-17,109
Thread-2,119
Thread-10,118
Thread-10,110
Thread-10,111
Thread-10,112
Thread-10,113
Thread-10,114
Thread-15,116
Thread-15,114
Thread-15,113
Thread-15,112
Thread-15,111
Thread-15,110
Thread-15,109
Thread-15,108
Thread-14,117
Thread-11,116
Thread-13,117
Thread-11,108
Thread-14,109
Thread-10,115
Thread-2,109
Thread-17,108
Thread-7,118
Thread-7,106
Thread-7,105
Thread-1,119
Thread-7,104
Thread-17,107
Thread-14,108
Thread-13,107
Thread-14,102
Thread-17,101
Thread-7,102
Thread-7,101
Thread-1,103
Thread-14,102
Thread-13,101
Thread-14,101
Thread-14,102
Thread-14,103
Thread-1,100
Thread-1,102
Thread-1,101
Thread-1,100
Disconnected from the target VM, address: '127.0.0.1:60088', transport: 'socket'

Process finished with exit code 0

可以看到,最后一个线程的最后一次操作,得到的值是 100,即所有线程的操作是对同一个变量进行的。每个线程对变量的改变,对于其他线程都是生效的

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3169 引用 • 8207 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...