import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * Created by Administrator on 2017/9/13. */ class Pair { //not thread-safe private int x, y; public Pair(int x, int y) { this.x = x; this.y = y; } public Pair() { this(0, 0); } public int getX() { return x; } public int getY() { return y; } public void incrementX() { x++; } public void incrementY() { y++; } public String toString() { return "x:" + x + ",y:" + y; } // RuntimeException 運行時異常。是全部Java虛擬機正常操做期間能夠被拋出的異常的父類 public class PairValueNotEqualException extends RuntimeException { public PairValueNotEqualException() { super("Pair values not equal:" + Pair.this); } } public void checkState() { if (x != y) throw new PairValueNotEqualException(); } } //Protect a Pair inside a thread-safe class abstract class PairManager { AtomicInteger checkCounter = new AtomicInteger(0); protected Pair p = new Pair(); private List<Pair> storage = Collections.synchronizedList(new ArrayList<Pair>()); public synchronized Pair getPair() { //make a copy to keep the original safe return new Pair(p.getX(), p.getY()); } //Assume this is a time consuming operation protected void store(Pair p) { storage.add(p); try { TimeUnit.MICROSECONDS.sleep(50); } catch (InterruptedException ignore) { } } public abstract void increment(); } //synchronize the entire method class PairManager1 extends PairManager { public synchronized void increment() { p.incrementX(); p.incrementY(); store(getPair()); } } //use a critical section: class PairManager2 extends PairManager { public void increment() { Pair temp; synchronized (this) { p.incrementX(); p.incrementY(); temp = getPair(); } store(temp); } } class PairManipulator implements Runnable { private PairManager pm; public PairManipulator(PairManager pm) { this.pm = pm; } public void run() { while (true) { pm.increment(); } } public String toString() { return "Pair: " + pm.getPair() + " checkCounter= " + pm.checkCounter.get(); } } class PairChecker implements Runnable { private PairManager pm; public PairChecker(PairManager pm) { this.pm = pm; } public void run() { while (true) { pm.checkCounter.incrementAndGet(); pm.getPair().checkState(); } } } public class CriticalSection { //Test the two different approaches: static void testApproaches(PairManager pman1, PairManager pman2) { ExecutorService exec = Executors.newCachedThreadPool(); PairManipulator pm1 = new PairManipulator(pman1); PairManipulator pm2 = new PairManipulator(pman2); PairChecker pcheck1 = new PairChecker(pman1); PairChecker pcheck2 = new PairChecker(pman2); exec.execute(pm1); exec.execute(pm2); exec.execute(pcheck1); exec.execute(pcheck2); try { TimeUnit.MICROSECONDS.sleep(500); } catch (InterruptedException e) { System.out.println("Sleep interrupted"); } System.out.println("pm1: " + pm1 + "\npm2: " + pm2); System.exit(0); } public static void main(String[] args) { PairManager pman1 = new PairManager1(); PairManager pman2 = new PairManager2(); testApproaches(pman1, pman2); } }
運行結果:java
Pair不是線程安全的,不能保證一個Pair對象在多線程程序中不會被破壞。npm
建立PairManager類,PairManager類持有一個Pair對象並控制對它的一切訪問。它的一些功能在基類中實現,而且其一個或多個抽象方法在派生類中定義,這種結構在設計模式中被稱爲模板方法。設計模式
經過checkCounter發現,同步控制塊不加鎖的時間短,這是寧願使用同步控制塊而不是對整個方法進行同步控制的典型緣由,使得其餘線程可以更多的訪問。安全
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Created by Administrator on 2017/9/13. */ class Pair { //not thread-safe private int x, y; public Pair(int x, int y) { this.x = x; this.y = y; } public Pair() { this(0, 0); } public int getX() { return x; } public int getY() { return y; } public void incrementX() { x++; } public void incrementY() { y++; } public String toString() { return "x:" + x + ",y:" + y; } // RuntimeException 運行時異常。是全部Java虛擬機正常操做期間能夠被拋出的異常的父類 public class PairValueNotEqualException extends RuntimeException { public PairValueNotEqualException() { super("Pair values not equal:" + Pair.this); } } public void checkState() { if (x != y) throw new PairValueNotEqualException(); } } //Protect a Pair inside a thread-safe class abstract class PairManager { AtomicInteger checkCounter = new AtomicInteger(0); protected Pair p = new Pair(); private List<Pair> storage = Collections.synchronizedList(new ArrayList<Pair>()); public synchronized Pair getPair() { //make a copy to keep the original safe return new Pair(p.getX(), p.getY()); } //Assume this is a time consuming operation protected void store(Pair p) { storage.add(p); try { TimeUnit.MICROSECONDS.sleep(50); } catch (InterruptedException ignore) { } } public abstract void increment(); } //synchronize the entire method class PairManager1 extends PairManager { public synchronized void increment() { p.incrementX(); p.incrementY(); store(getPair()); } } //use a critical section: class PairManager2 extends PairManager { public void increment() { Pair temp; synchronized (this) { p.incrementX(); p.incrementY(); temp = getPair(); } store(temp); } } //synchronize the entire method class ExplicitPairManager1 extends PairManager { private Lock lock = new ReentrantLock(); public synchronized void increment() { lock.lock(); try { p.incrementX(); p.incrementY(); store(getPair()); } finally { lock.unlock(); } } } //use a critical section class ExplicitPairManager2 extends PairManager { private Lock lock = new ReentrantLock(); public void increment() { Pair temp; lock.lock(); try { p.incrementX(); p.incrementY(); temp = getPair(); } finally { lock.unlock(); } store(temp); } } class PairManipulator implements Runnable { private PairManager pm; public PairManipulator(PairManager pm) { this.pm = pm; } public void run() { while (true) { pm.increment(); } } public String toString() { return "Pair: " + pm.getPair() + " checkCounter= " + pm.checkCounter.get(); } } class PairChecker implements Runnable { private PairManager pm; public PairChecker(PairManager pm) { this.pm = pm; } public void run() { while (true) { pm.checkCounter.incrementAndGet(); pm.getPair().checkState(); } } } public class CriticalSection { //Test the two different approaches: static void testApproaches(PairManager pman1, PairManager pman2) { ExecutorService exec = Executors.newCachedThreadPool(); PairManipulator pm1 = new PairManipulator(pman1); PairManipulator pm2 = new PairManipulator(pman2); PairChecker pcheck1 = new PairChecker(pman1); PairChecker pcheck2 = new PairChecker(pman2); exec.execute(pm1); exec.execute(pm2); exec.execute(pcheck1); exec.execute(pcheck2); try { TimeUnit.MICROSECONDS.sleep(500); } catch (InterruptedException e) { System.out.println("Sleep interrupted"); } System.out.println("pm1: " + pm1 + "\npm2: " + pm2); System.exit(0); } public static void main(String[] args) throws Exception{ /*PairManager pman1 = new PairManager1(); PairManager pman2 = new PairManager2();*/ PairManager pman1 = new ExplicitPairManager1(); PairManager pman2 = new ExplicitPairManager2(); testApproaches(pman1, pman2); } }