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 = ""; @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; // } }
注意到在产生偶数是要加同步锁,否则可能线程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++; } @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); } } } }
注意i++操作并不是原子行操作,getValue() 方法也要加synchronized 。