Mega Code Archive

 
Categories / Java / Threads
 

Synchronizing blocks instead of entire methods

// : c13:CriticalSection.java // Synchronizing blocks instead of entire methods. Also // demonstrates protection of a non-thread-safe class // with a thread-safe one. // From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002 // www.BruceEckel.com. See copyright notice in CopyRight.txt. import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class CriticalSection {   public static void main(String[] args) {     // Test the two different approaches:     final PairManipulator pm1 = new PairManipulator(new PairManager1()), pm2 = new PairManipulator(         new PairManager2());     new Timer(true).schedule(new TimerTask() {       public void run() {         System.out.println("pm1: " + pm1);         System.out.println("pm2: " + pm2);         System.exit(0);       }     }, 500); // run() after 500 milliseconds   } } ///:~ 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;   }   public class PairValuesNotEqualException extends RuntimeException {     public PairValuesNotEqualException() {       super("Pair values not equal: " + Pair.this);     }   }   // Arbitrary invariant -- both variables must be equal:   public void checkState() {     if (x != y)       throw new PairValuesNotEqualException();   } } // Protect a Pair inside a thread-safe class: abstract class PairManager {   protected Pair p = new Pair();   private List storage = new ArrayList();   public synchronized Pair getPair() {     // Make a copy to keep the original safe:     return new Pair(p.getX(), p.getY());   }   protected void store() {     storage.add(getPair());   }   // A "template method":   public abstract void doTask(); } // Synchronize the entire method: class PairManager1 extends PairManager {   public synchronized void doTask() {     p.incrementX();     p.incrementY();     store();   } } // Use a critical section: class PairManager2 extends PairManager {   public void doTask() {     synchronized (this) {       p.incrementX();       p.incrementY();     }     store();   } } class PairManipulator extends Thread {   private PairManager pm;   private int checkCounter = 0;   private class PairChecker extends Thread {     PairChecker() {       start();     }     public void run() {       while (true) {         checkCounter++;         pm.getPair().checkState();       }     }   }   public PairManipulator(PairManager pm) {     this.pm = pm;     start();     new PairChecker();   }   public void run() {     while (true) {       pm.doTask();     }   }   public String toString() {     return "Pair: " + pm.getPair() + " checkCounter = " + checkCounter;   } }