首页 > 代码库 > java多线程总结四:volatile、synchronized示例

java多线程总结四:volatile、synchronized示例

1、synchronized保证同步

先看一个生成偶数的类

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.thread;  
  2.   
  3. /** 
  4.  *这是一个int生成器的抽象类 
  5.  *  
  6.  */  
  7. public abstract class IntGenerator {  
  8.       
  9.     private volatile boolean canceled = false;  
  10.   
  11.     public abstract int next();  
  12.   
  13.     public void cancel() {  
  14.         canceled = true;  
  15.     }  
  16.   
  17.     public boolean isCanceled() {  
  18.         return canceled;  
  19.     }  
  20. }  
  21. </span>  


 

[java] view plaincopy
  1. <span style="font-size:16px;">/* 
  2.  * 产生偶数 
  3.  */  
  4. class EvenGenerator extends IntGenerator {  
  5.     private int currentEvenValue = 0;  
  6.     String s = "";  
  7.   
  8.     @Override  
  9.     public int next() {  
  10.         <span style="color:#ff0000;">synchronized </span>(s) {  
  11.             ++currentEvenValue;  
  12.             ++currentEvenValue;  
  13.             return currentEvenValue;  
  14.         }  
  15.     }  
  16.   
  17. //  //这样也可以  
  18. //  public <span style="color:#ff0000;">synchronized </span>int next() {  
  19. //          ++currentEvenValue;  
  20. //          ++currentEvenValue;  
  21. //          return currentEvenValue;  
  22. //  }  
  23. }</span>  


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

测试代码:

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.thread;  
  2.   
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. /* 
  7.  * 消费数字 
  8.  */  
  9. public class EvenChecker implements Runnable {  
  10.       
  11.     private IntGenerator generator;  
  12.     private final int id;  
  13.   
  14.     public EvenChecker(IntGenerator g, int ident) {  
  15.         generator = g;  
  16.         id = ident;  
  17.     }  
  18.   
  19.     public void run() {  
  20.         while (!generator.isCanceled()) {  
  21.             int val = generator.next();  
  22.             if (val % 2 != 0) {//如果不是偶数  
  23.                 System.out.println(val + " not enen!");  
  24.                 generator.cancel();  
  25.             }  
  26.         }  
  27.     }  
  28.   
  29.     public static void test(IntGenerator gp, int count) {  
  30.         ExecutorService exec = Executors.newCachedThreadPool();  
  31.         for (int i = 0; i < count; i++)  
  32.             exec.execute(new EvenChecker(gp, i));  
  33.         exec.shutdown();  
  34.     }  
  35.   
  36.     public static void test(IntGenerator gp) {  
  37.         test(gp, 10);  
  38.     }  
  39.   
  40.     public static void main(String[] args) {  
  41.         test(new EvenGenerator());  
  42.     }  
  43. }</span>  


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

 

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

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

     代码示例:

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.thread;  
  2.   
  3. public class VolatileDemo implements Runnable {  
  4.       
  5.     private volatile int i = 0;//volatile设置可见性  
  6.   
  7.     public synchronized  int getValue() {  
  8.         return i;  
  9.     }  
  10.   
  11.     private synchronized void enenIncrement() {  
  12.         i++;  
  13.         i++;  
  14.     }  
  15.   
  16.     @Override  
  17.     public void run() {  
  18.         while (true)  
  19.             enenIncrement();  
  20.     }  
  21.   
  22.     public static void main(String[] args) {  
  23.         VolatileDemo at = new VolatileDemo();  
  24.         new Thread(at).start();  
  25.         while (true) {  
  26.             int val = at.getValue();  
  27.             if (val % 2 != 0) {//出现奇数,退出程序  
  28.                 System.out.println(val+" is not enen!");  
  29.                 System.exit(0);  
  30.             }  
  31.         }  
  32.   
  33.     }  
  34. }  
  35. </span>  


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

java多线程总结四:volatile、synchronized示例