Java:volatile

Java中的原子性操做與同步問題java

1.在Java中,原子操做是指不能被線程調度機制中斷的操做,一旦操做開始,那麼它必定能夠在可能發生的"上下文切換"以前(切換到其它線程執行)執行完畢。ide

2.依賴原子性來處理同步問題時很棘手而且很危險的事情。spa

以下面的程序,儘管return i;確實是原子性操做,可是缺乏同步使得其數值能夠在處於不穩定的中間狀態時被讀取,儘管變量i添加上了volatile關鍵字。線程

正確的方法時同時將getValue()和evenIncrement()都是synchronized的。3d

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 
 4 
 5 public class AtomicityTest implements Runnable {
 6 
 7     private int i = 0;
 8     
 9     public int getValue() {
10         return i;
11     }
12     
13     private synchronized void evenIncrement() {
14         i++;
15         i++;
16     }
17     
18     @Override
19     public void run() {
20         while (true) {
21             evenIncrement();
22         }
23     }
24     
25     public static void main(String[] args) {
26         ExecutorService exec = Executors.newCachedThreadPool();
27         AtomicityTest at = new AtomicityTest();
28         exec.execute(at);
29         while (true) {
30             int val = at.getValue();
31             if (val % 2 != 0) {
32                 System.out.println("error..." + val + " is odd.");
33                 System.exit(0);
34             }
35         }
36  
37     }
38 
39 }
40 /**
41  * 程序運行結果:
42  * error...53683 is odd.
43  */
AtomicityTest.java

再以下面的程序,一方面雖然用volatile關鍵字修飾了SerialNumberGenerator.serialNumber成員,可是nextSerialNumber()中的++運算並非原子操做,因此仍是會出現問題。code

解決問題得方法就是把nextSerialNumber()方法改成synchronized的。blog

1 public class SerialNumberGenerator {
2     
3     private static volatile int serialNumber = 0;
4     
5     public static int nextSerialNumber() {
6         return serialNumber++;
7     }
8 }
SerialNumberGenerator.java

 1 public class CircularSet {
 2     
 3     private int[] array;
 4     private int len;
 5     private int index = 0;
 6     
 7     public CircularSet(int size) {
 8         array = new int[size];
 9         len = size;
10         for (int i = 0; i < len; i++) array[i] = -1;
11     }
12     
13     public synchronized void add(int i) { 
14         array[index] = i;
15         index = (index + 1) % len;
16     }
17     
18     public synchronized boolean contains(int val) {
19         for (int i = 0; i < len; i++) {
20             if (array[i] == val) return true;
21         }
22         return false;
23     }
24 
25 }
CircularSet.java

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 
 4 
 5 public class SerialNumberChecker {
 6     
 7     private static final int SIZE = 10;
 8     private static CircularSet serials = new CircularSet(1000);
 9     private static ExecutorService exec = Executors.newCachedThreadPool();
10     
11     public static void main(String[] args) {
12         
13         for (int i = 0; i < SIZE; i++) {
14             exec.execute(new Runnable() {
15 
16                 @Override
17                 public void run() {
18                     while (true) {
19                         int serial = SerialNumberGenerator.nextSerialNumber();
20                         if (serials.contains(serial)) {
21                             System.out.println("error... " + serial + " duplicate.");
22                             System.exit(0);
23                         }
24                         serials.add(serial);
25                     }
26                 }
27                 
28             });
29         }
30     }
31 
32 }
33 
34 /**
35  * 程序執行結果:
36  * error... 8298 duplicate.
37  * error... 9049 duplicate.
38  * error... 9051 duplicate.
39  * error... 9045 duplicate.
40  * error... 9050 duplicate.
41  * error... 9048 duplicate.
42  * error... 9047 duplicate.
43  * error... 9046 duplicate.
44  */
SerialNumberChecker.java
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息