`

原子量

    博客分类:
  • java
阅读更多
所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的。
 
为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题。在Java5之前,可以通过volatile、synchronized关键字来解决并发访问的安全问题,但这样太麻烦。
Java5之后,专门提供了用来进行单变量多线程并发安全访问的工具包java.util.concurrent.atomic,其中的类也很简单。
 
下面给出一个反面例子(切勿模仿):
Java代码 复制代码
  1. import java.util.concurrent.ExecutorService;    
  2. import java.util.concurrent.Executors;    
  3. import java.util.concurrent.atomic.AtomicLong;    
  4.   
  5. /**   
  6. * Java线程:新特征-原子量   
  7.  
  8. * @author leizhimin 2009-11-6 9:53:11   
  9. */    
  10. public class Test {    
  11.         public static void main(String[] args) {    
  12.                 ExecutorService pool = Executors.newFixedThreadPool(2);    
  13.                 Runnable t1 = new MyRunnable("张三"2000);    
  14.                 Runnable t2 = new MyRunnable("李四"3600);    
  15.                 Runnable t3 = new MyRunnable("王五"2700);    
  16.                 Runnable t4 = new MyRunnable("老张"600);    
  17.                 Runnable t5 = new MyRunnable("老牛"1300);    
  18.                 Runnable t6 = new MyRunnable("胖子"800);    
  19.                 //执行各个线程    
  20.                 pool.execute(t1);    
  21.                 pool.execute(t2);    
  22.                 pool.execute(t3);    
  23.                 pool.execute(t4);    
  24.                 pool.execute(t5);    
  25.                 pool.execute(t6);    
  26.                 //关闭线程池    
  27.                 pool.shutdown();    
  28.         }    
  29. }    
  30.   
  31. class MyRunnable implements Runnable {    
  32.         private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作    
  33.         private String name;                //操作人    
  34.         private int x;                            //操作数额    
  35.   
  36.         MyRunnable(String name, int x) {    
  37.                 this.name = name;    
  38.                 this.x = x;    
  39.         }    
  40.   
  41.         public void run() {    
  42.                 System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x));    
  43.         }    
  44. }  
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.atomic.AtomicLong; 

/** 
* Java线程:新特征-原子量 
* 
* @author leizhimin 2009-11-6 9:53:11 
*/ 
public class Test { 
        public static void main(String[] args) { 
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Runnable t1 = new MyRunnable("张三", 2000); 
                Runnable t2 = new MyRunnable("李四", 3600); 
                Runnable t3 = new MyRunnable("王五", 2700); 
                Runnable t4 = new MyRunnable("老张", 600); 
                Runnable t5 = new MyRunnable("老牛", 1300); 
                Runnable t6 = new MyRunnable("胖子", 800); 
                //执行各个线程 
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池 
                pool.shutdown(); 
        } 
} 

class MyRunnable implements Runnable { 
        private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作 
        private String name;                //操作人 
        private int x;                            //操作数额 

        MyRunnable(String name, int x) { 
                this.name = name; 
                this.x = x; 
        } 

        public void run() { 
                System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x)); 
        } 
}
 运行结果:
Java代码 复制代码
  1. 李四执行了3600,当前余额:13600    
  2. 王五执行了2700,当前余额:16300    
  3. 老张执行了600,当前余额:16900    
  4. 老牛执行了1300,当前余额:18200    
  5. 胖子执行了800,当前余额:19000    
  6. 张三执行了2000,当前余额:21000    
  7.   
  8. Process finished with exit code 0  
李四执行了3600,当前余额:13600 
王五执行了2700,当前余额:16300 
老张执行了600,当前余额:16900 
老牛执行了1300,当前余额:18200 
胖子执行了800,当前余额:19000 
张三执行了2000,当前余额:21000 

Process finished with exit code 0
 
Java代码 复制代码
  1. 张三执行了2000,当前余额:12000    
  2. 王五执行了2700,当前余额:18300    
  3. 老张执行了600,当前余额:18900    
  4. 老牛执行了1300,当前余额:20200    
  5. 胖子执行了800,当前余额:21000    
  6. 李四执行了3600,当前余额:15600    
  7.   
  8. Process finished with exit code 0  
张三执行了2000,当前余额:12000 
王五执行了2700,当前余额:18300 
老张执行了600,当前余额:18900 
老牛执行了1300,当前余额:20200 
胖子执行了800,当前余额:21000 
李四执行了3600,当前余额:15600 

Process finished with exit code 0
 
Java代码 复制代码
  1. 张三执行了2000,当前余额:12000    
  2. 李四执行了3600,当前余额:15600    
  3. 老张执行了600,当前余额:18900    
  4. 老牛执行了1300,当前余额:20200    
  5. 胖子执行了800,当前余额:21000    
  6. 王五执行了2700,当前余额:18300    
  7.   
  8. Process finished with exit code 0  
张三执行了2000,当前余额:12000 
李四执行了3600,当前余额:15600 
老张执行了600,当前余额:18900 
老牛执行了1300,当前余额:20200 
胖子执行了800,当前余额:21000 
王五执行了2700,当前余额:18300 

Process finished with exit code 0
 
从运行结果可以看出,虽然使用了原子量,但是程序并发访问还是有问题,那究竟问题出在哪里了?
 
这里要注意的一点是,原子量虽然可以保证单个变量在某一个操作过程的安全,但无法保证你整个代码块,或者整个程序的安全性。因此,通常还应该使用锁等同步机制来控制整个程序的安全性。
 
下面是对这个错误修正:
Java代码 复制代码
  1. import java.util.concurrent.ExecutorService;    
  2. import java.util.concurrent.Executors;    
  3. import java.util.concurrent.locks.Lock;    
  4. import java.util.concurrent.locks.ReentrantLock;    
  5. import java.util.concurrent.atomic.AtomicLong;    
  6.   
  7. /**   
  8. * Java线程:新特征-原子量   
  9.  
  10. * @author leizhimin 2009-11-6 9:53:11   
  11. */    
  12. public class Test {    
  13.         public static void main(String[] args) {    
  14.                 ExecutorService pool = Executors.newFixedThreadPool(2);    
  15.                 Lock lock = new ReentrantLock(false);    
  16.                 Runnable t1 = new MyRunnable("张三"2000,lock);    
  17.                 Runnable t2 = new MyRunnable("李四"3600,lock);    
  18.                 Runnable t3 = new MyRunnable("王五"2700,lock);    
  19.                 Runnable t4 = new MyRunnable("老张"600,lock);    
  20.                 Runnable t5 = new MyRunnable("老牛"1300,lock);    
  21.                 Runnable t6 = new MyRunnable("胖子"800,lock);    
  22.                 //执行各个线程    
  23.                 pool.execute(t1);    
  24.                 pool.execute(t2);    
  25.                 pool.execute(t3);    
  26.                 pool.execute(t4);    
  27.                 pool.execute(t5);    
  28.                 pool.execute(t6);    
  29.                 //关闭线程池    
  30.                 pool.shutdown();    
  31.         }    
  32. }    
  33.   
  34. class MyRunnable implements Runnable {    
  35.         private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作    
  36.         private String name;                //操作人    
  37.         private int x;                            //操作数额    
  38.         private Lock lock;    
  39.   
  40.         MyRunnable(String name, int x,Lock lock) {    
  41.                 this.name = name;    
  42.                 this.x = x;    
  43.                 this.lock = lock;    
  44.         }    
  45.   
  46.         public void run() {    
  47.                 lock.lock();    
  48.                 System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x));    
  49.                 lock.unlock();    
  50.         }    
  51. }  
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
import java.util.concurrent.atomic.AtomicLong; 

/** 
* Java线程:新特征-原子量 
* 
* @author leizhimin 2009-11-6 9:53:11 
*/ 
public class Test { 
        public static void main(String[] args) { 
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Lock lock = new ReentrantLock(false); 
                Runnable t1 = new MyRunnable("张三", 2000,lock); 
                Runnable t2 = new MyRunnable("李四", 3600,lock); 
                Runnable t3 = new MyRunnable("王五", 2700,lock); 
                Runnable t4 = new MyRunnable("老张", 600,lock); 
                Runnable t5 = new MyRunnable("老牛", 1300,lock); 
                Runnable t6 = new MyRunnable("胖子", 800,lock); 
                //执行各个线程 
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池 
                pool.shutdown(); 
        } 
} 

class MyRunnable implements Runnable { 
        private static AtomicLong aLong = new AtomicLong(10000);        //原子量,每个线程都可以自由操作 
        private String name;                //操作人 
        private int x;                            //操作数额 
        private Lock lock; 

        MyRunnable(String name, int x,Lock lock) { 
                this.name = name; 
                this.x = x; 
                this.lock = lock; 
        } 

        public void run() { 
                lock.lock(); 
                System.out.println(name + "执行了" + x + ",当前余额:" + aLong.addAndGet(x)); 
                lock.unlock(); 
        } 
}
 
执行结果:
Java代码 复制代码
  1. 张三执行了2000,当前余额:12000    
  2. 王五执行了2700,当前余额:14700    
  3. 老张执行了600,当前余额:15300    
  4. 老牛执行了1300,当前余额:16600    
  5. 胖子执行了800,当前余额:17400    
  6. 李四执行了3600,当前余额:21000    
  7.   
  8. Process finished with exit code 0  
张三执行了2000,当前余额:12000 
王五执行了2700,当前余额:14700 
老张执行了600,当前余额:15300 
老牛执行了1300,当前余额:16600 
胖子执行了800,当前余额:17400 
李四执行了3600,当前余额:21000 

Process finished with exit code 0
 
这里使用了一个对象锁,来控制对并发代码的访问。不管运行多少次,执行次序如何,最终余额均为21000,这个结果是正确的。
 
有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的。
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    中文版元素周期表及其原子量信息详解

    内容概要:本文档详细列出了标准元素周期表的所有元素,包括每个元素的原子序数、元素符号、元素中文名称、惯用原子量和标准原子量范围,以及部分元素的同位素信息。元素周期表还特别标明了镧系元素和锕系元素,并...

    原子量的测定发展史[参考].pdf

    1. 原子量测定的起源:原子量的测定始于19世纪初,由英国化学家约翰·道尔顿提出。道尔顿的原子论是化学史上一个重要的里程碑,他在1803年首次公布了一些元素的原子相对重量,尽管这些数据并不精确,但它们为后续的...

    初中化学化学家为测定元素原子量而立功的里查兹

    在化学的发展历程中,测定元素原子量的工作一直是基础科学研究的重中之重。美国化学家西奥多·威廉·里查兹(Theodore William Richards)在这一领域所作的贡献,无疑为我们理解元素的化学性质和行为提供了不可或缺...

    高一化学上学期原子量物质量新教人PPT学习教案.pptx

    在高中化学的学习中,原子量和物质量是基础且重要的概念,它们与阿伏加德罗常数密切相关。阿伏加德罗常数是一个在化学领域至关重要的数值,由意大利物理学家阿伏加德罗提出,它定义为12克碳-12同位素中所含碳原子的...

    元素周期表_原子量 2017最新版

    元素周期表(原子量) 2017最新版

    本文件是 c++20 规范, vs2019 上的 <atomic> 头文件,带注释 原子量,多线程中保护原子变量

    本文件是 c++20 规范, vs2019 上的 &lt;atomic&gt; 头文件,带注释。原子量,多线程中保护原子变量

    C++11中的原子量和内存序详解

    主要给大家介绍了关于C++11中原子量和内存序的相关资料,文中通过示例代码介绍地方非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    利用C++11原子量如何实现自旋锁详解

    C++11原子量在实现自旋锁中的应用 自旋锁是一种低级同步机制,它允许多个线程在尝试访问共享资源时保持活跃,而不是立即进入睡眠状态。自旋锁的核心思想是,当一个线程试图获取锁时,它会不断地检查锁的状态,直到...

    amolwt:元素的原子量或化学物质的分子量。-matlab开发

    在MATLAB编程环境中,"amolwt"是一个用于计算元素原子量或化学物质分子量的M文件。这个功能对于化学、物理以及相关科学领域的计算工作非常有用,特别是涉及到化学反应和分子组成的分析时。下面我们将深入探讨这个...

    Inorganic-Chemistry 第六版.pdf

    - **原子量**(Atomic Mass):表示元素的平均原子质量,通常以统一原子质量单位(u)表示。 #### 3. 主族元素示例 - **氢(H)**:原子序数1,原子量1.0079。 - **氦(He)**:原子序数2,原子量4.00。 - **锂(Li...

    高一化学原子核测试[精选].doc

    16. **金属与酸的反应**:金属与酸反应生成氢气,通过金属的质量、酸的浓度和体积,结合原子量的比例关系,可以推算出金属的种类和原子量,以及它们的元素身份。 通过以上知识点的解析,我们可以理解高一化学中关于...

    数据结构课程设计 求分子量

    分子式是用来表达分子组成结构的表达式,一般...例如N的原子量为14,H的原子量为1,C的原子量为12,O的原子量为16,因此(NH4)2CO3的分子量为(14+1*4)*2+12+16*3=96。试编写程序求出给定的各个分子式所对应的分子量。

    原子结构元素周期律和周期表.doc

    - 原子量可以是同位素的原子量,元素的平均原子量,或近似平均原子量。 - 平均原子量考虑了所有同位素的相对丰度和质量数。 8. 实际应用示例: - 通过不同分子量的比例可以推断元素的同位素种类和比例,如例2中...

    元素周期表发展史.pdf

    1829年,德国科学家德贝莱纳提出了三元素组规则,他发现特定的元素之间存在类似的性质,并且这些三元素组中间元素的原子量往往接近于两端元素原子量的平均值。这一规则为后来元素周期律的发现奠定了基础。 随后,...

    化学元素周期表的发展史定义.pdf

    道尔顿在1803年提出了原子量的概念,但因为测量方法的不精确,导致原子量的混乱。德贝莱纳在1829年研究了原子量与化学性质的关系,而培顿科弗和格拉斯顿则发现了元素组的规律。 1850年代,类似的研究继续进行,如...

    分子量计算器

    例如,对于水分子(H2O),其分子量为2(氢的原子量)×2 + 16(氧的原子量)= 32.00。这个简单的例子展示了分子量计算器如何简化复杂化学式的计算过程,尤其对于含有多种元素的大分子,手动计算可能会非常繁琐。 ...

    matlab开发-amolwt

    在MATLAB环境中进行科学计算和数据分析时,常常需要处理化学元素和化合物的原子量或分子量。"matlab开发-amolwt"项目就是一个专门用于计算这些重量的工具包。这个工具包包含了一些关键的MATLAB脚本和数据文件,帮助...

    元素周期律发展史.doc

    接着,培顿科弗提出了原子量差为8或其倍数的假设,而尚古多通过《螺旋图》将元素按照原子量排列,发现了化学性质相似的元素出现在同一条直线上。 1864年,德国化学家迈耶尔发表了他的《六元素表》,这是他在化合价...

    元素周期表发展史PPT课件.pptx

    门捷列夫的周期表成功地预测了元素的性质,如碘的原子量小于其前一个元素溴,这与当时测定的原子量不符,但门捷列夫坚持这一预测,最终被证实正确。 19世纪末,门捷列夫的周期表经过多次修订和完善,尤其是在发现...

Global site tag (gtag.js) - Google Analytics