zoukankan      html  css  js  c++  java
  • Java:volatile

    Java中的原子性操作与同步问题

    1.在Java中,原子操作是指不能被线程调度机制中断的操作,一旦操作开始,那么它一定可以在可能发生的"上下文切换"之前(切换到其它线程执行)执行完毕。

    2.依赖原子性来处理同步问题时很棘手并且很危险的事情。

    如下面的程序,尽管return i;确实是原子性操作,但是缺少同步使得其数值可以在处于不稳定的中间状态时被读取,尽管变量i添加上了volatile关键字。

    正确的方法时同时将getValue()和evenIncrement()都是synchronized的。

     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()中的++运算并不是原子操作,所以还是会出现问题。

    解决问题得方法就是把nextSerialNumber()方法改为synchronized的。

    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

  • 相关阅读:
    文字编码
    各个地区的编码
    Android中调用系统所装的软件打开文件
    Android中检测手机制式和移动网络类型
    Android使用ContentProvide(内容提供者)向其他应用程序共享数据
    windows Phone Push Notification
    解决Android加载图片时内存溢出的问题
    Android 正则表达式
    淡定
    Android简单数据存储类SharedPreferences详解及实例
  • 原文地址:https://www.cnblogs.com/slowalker/p/3379262.html
Copyright © 2011-2022 走看看