Java多线程之原子性 volatile、atomicInteger测试

原文连接:http://www.cnblogs.com/zhengbin/p/5653051.html

1、补充概念


1.什么是线程安全性?html

  《Java Concurrency in Practice》中有提到:当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。java

2.Java中的“同步”安全

  Java中的主要同步机制是关键字“synchronized”,它提供了一种独占的加锁方式,但“同步”这个术语还包括volatile类型的变量,显式锁(Explicit Lock)以及原子变量。多线程

2.原子性工具

  原子是世界上的最小单位,具备不可分割性。好比 a=0;(a非long和double类型)这个操做是不可分割的,那么咱们说这个操做时原子操做。再好比:a++;这个操做实际是a = a + 1;是可分割的,因此他不是一个原子操做。非原子操做都会存在线程安全问题,须要咱们使用同步技术(sychronized)来让它变成一个原子操做。一个操做是原子操做,那么咱们称它具备原子性。java的concurrent包下提供了一些原子类,咱们能够经过阅读API来了解这些原子类的用法。好比:AtomicInteger、AtomicLong、AtomicReference等。atom

2、实例源码


 1 public class IncrementTestDemo {
 2 
 3     public static int count = 0;
 4     public static Counter counter = new Counter();
 5     public static AtomicInteger atomicInteger = new AtomicInteger(0);
 6     volatile public static int countVolatile = 0;
 7     
 8     public static void main(String[] args) {
 9         for (int i = 0; i < 10; i++) {
10             new Thread() {
11                 public void run() {
12                     for (int j = 0; j < 1000; j++) {
13                         count++;
14                         counter.increment();
15                         atomicInteger.getAndIncrement();
16                         countVolatile++;
17                     }
18                 }
19             }.start();
20         }
21         try {
22             Thread.sleep(3000);
23         } catch (InterruptedException e) {
24             e.printStackTrace();
25         }
26         
27         System.out.println("static count: " + count);
28         System.out.println("Counter: " + counter.getValue());
29         System.out.println("AtomicInteger: " + atomicInteger.intValue());
30         System.out.println("countVolatile: " + countVolatile);
31     }
32     
33 }
34 
35 class Counter {
36     private int value;
37 
38     public synchronized int getValue() {
39         return value;
40     }
41 
42     public synchronized int increment() {
43         return ++value;
44     }
45 
46     public synchronized int decrement() {
47         return --value;
48     }
49 }
复制代码

  输出结果:spa

+ View code
static count: 9952
Counter: 10000
AtomicInteger: 10000
countVolatile: 9979
 

  第一行与最后一行,每次运行将获得不一样的结果,可是中间两行的结果相同。线程

  经过上面的例子说明,要解决自增操做在多线程环境下线程不安全的问题,能够选择使用Java提供的原子类,或者使用synchronized同步方法。code

  而经过Volatile关键字,并不能解决非原子操做的线程安全性。Volatile详解htm

3、Java中的自增原理


  虽然递增操做++i是一种紧凑的语法,使其看上去只是一个操做,但这个操做并不是原子的,于是它并不会做为一个不可分割的操做来执行。实际上,它包含了三个独立的操做:读取count的值,将值加1,而后将计算结果写入count。这是一个“读取 - 修改 - 写入”的操做序列,而且其结果状态依赖于以前的状态。

  下面写一个简单的类,用jdk中的工具javap来反编译Java字节码文件。

/**
 * @author zhengbinMac
 */
public class TestDemo {
    public static int count;

    public void code() {
        count++;
    }
}
复制代码
localhost:Increment zhengbinMac$ javap -c TestDemo
警告: 二进制文件TestDemo包含Increment.TestDemo
Compiled from "TestDemo.java"
public class Increment.TestDemo {
  public static int count;

  public Increment.TestDemo();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public void code();
    Code:
       0: getstatic     #2                  // Field count:I
       3: iconst_1      
       4: iadd          
       5: putstatic     #2                  // Field count:I
       8: return        
}
复制代码

  如上字节码,咱们发现自增操做包括取数(getstatic  #2)、加一(iconst_1和iadd)、保存(putstatic  #2),并非咱们认为的一条机器指令搞定的。

相关文章
相关标签/搜索