volatile、synchronized示例

1、synchronized保证同步

先看一个生成偶数的类
[java] view plaincopy

    <span style="font-size:16px;">package demo.thread; 
     
    /**
     *这是一个int生成器的抽象类
     * 
     */ 
    public abstract class IntGenerator { 
         
        private volatile boolean canceled = false; 
     
        public abstract int next(); 
     
        public void cancel() { 
            canceled = true; 
        } 
     
        public boolean isCanceled() { 
            return canceled; 
        } 
    } 
    </span> 


 
[java] view plaincopy

    <span style="font-size:16px;">/*
     * 产生偶数
     */ 
    class EvenGenerator extends IntGenerator { 
        private int currentEvenValue = 0; 
        String s = ""; 
     
        @Override 
        public int next() { 
            <span style="color:#ff0000;">synchronized </span>(s) { 
                ++currentEvenValue; 
                ++currentEvenValue; 
                return currentEvenValue; 
            } 
        } 
     
    //  //这样也可以 
    //  public <span style="color:#ff0000;">synchronized </span>int next() { 
    //          ++currentEvenValue; 
    //          ++currentEvenValue; 
    //          return currentEvenValue; 
    //  } 
    }</span> 


注意到在产生偶数是要加同步锁,否则可能线程1刚好执行了一句++currentEvenValue;操作,就被线程2抢去了cpu,此时线程2执行return currentEvenValue;这时返回的就是一个奇数。加synchronized 就是两个线程同时只能一个线程执行synchronized 块的代码。

测试代码:
[java] view plaincopy

    <span style="font-size:16px;">package demo.thread; 
     
    import java.util.concurrent.ExecutorService; 
    import java.util.concurrent.Executors; 
     
    /*
     * 消费数字
     */ 
    public class EvenChecker implements Runnable { 
         
        private IntGenerator generator; 
        private final int id; 
     
        public EvenChecker(IntGenerator g, int ident) { 
            generator = g; 
            id = ident; 
        } 
     
        public void run() { 
            while (!generator.isCanceled()) { 
                int val = generator.next(); 
                if (val % 2 != 0) {//如果不是偶数 
                    System.out.println(val + " not enen!"); 
                    generator.cancel(); 
                } 
            } 
        } 
     
        public static void test(IntGenerator gp, int count) { 
            ExecutorService exec = Executors.newCachedThreadPool(); 
            for (int i = 0; i < count; i++) 
                exec.execute(new EvenChecker(gp, i)); 
            exec.shutdown(); 
        } 
     
        public static void test(IntGenerator gp) { 
            test(gp, 10); 
        } 
     
        public static void main(String[] args) { 
            test(new EvenGenerator()); 
        } 
    }</span> 


分析:如果产生偶数的类未加synchronized,那么测试程序将会出现奇数导致退出程序。

2、volatile表示原子性,可见性。

      对于多个线程之间共享的变量,每个线程都有自己的一份拷贝,当线程1改变变量值时,其他线程并不马上知道该变量值改变了,volatile就保证了变量值对各个线程可见,一个线程改变该值,马上其他线程中该值也改变。原子性表明操作不可中断,如基本变量赋值。

     代码示例:
[java] view plaincopy

    <span style="font-size:16px;">package demo.thread; 
     
    public class VolatileDemo implements Runnable { 
         
        private volatile int i = 0;//volatile设置可见性 
     
        public synchronized  int getValue() { 
            return i; 
        } 
     
        private synchronized void enenIncrement() { 
            i++; 
            i++; 
        } 
     
        @Override 
        public void run() { 
            while (true) 
                enenIncrement(); 
        } 
     
        public static void main(String[] args) { 
            VolatileDemo at = new VolatileDemo(); 
            new Thread(at).start(); 
            while (true) { 
                int val = at.getValue(); 
                if (val % 2 != 0) {//出现奇数,退出程序 
                    System.out.println(val+" is not enen!"); 
                    System.exit(0); 
                } 
            } 
     
        } 
    } 
    </span> 


注意i++操作并不是原子行操作,getValue() 方法也要加synchronized 。

猜你喜欢

转载自zhoshijie.iteye.com/blog/2009155