1、synchronized保證同步
先看一個產生偶數的類
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;}}
/* * 產生偶數 */class EvenGenerator extends IntGenerator {private int currentEvenValue = 0;String s = "";@Overridepublic int next() {synchronized (s) {++currentEvenValue;++currentEvenValue;return currentEvenValue;}}////這樣也可以//public synchronized int next() {//++currentEvenValue;//++currentEvenValue;//return currentEvenValue;//}}
注意到在產生偶數是要加同步鎖,否則可能線程1剛好執行了一句++currentEvenValue;操作,就被線程2搶去了cpu,此時線程2執行return currentEvenValue;這時返回的就是一個奇數。加synchronized
就是兩個線程同時只能一個線程執行synchronized 塊的代碼。
測試代碼:
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());}}
分析:如果產生偶數的類未加synchronized,那麼測試程式將會出現奇數導致退出程式。
2、volatile表示原子性,可見度。
對於多個線程之間共用的變數,每個線程都有自己的一份拷貝,當線程1改變變數值時,其他線程並不馬上知道該變數值改變了,volatile就保證了變數值對各個線程可見,一個線程改變該值,馬上其他線程中該值也改變。原子性表明操作不可中斷,如基本變數賦值。
程式碼範例:
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++;}@Overridepublic 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);}}}}
注意i++操作並不是原子行操作,getValue() 方法也要加synchronized 。