Presentation is loading. Please wait.

Presentation is loading. Please wait.

Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 1 Reducing synchronization.

Similar presentations


Presentation on theme: "Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 1 Reducing synchronization."— Presentation transcript:

1 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 1 Reducing synchronization

2 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 2 Removing synchronization from queries Two issues to consider to safely remove it: –Legality: value of field never assumes an illegal value. –Staleness: clients do not necessarily require latest updated value, can live with stale value.

3 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 3 Not always legal field value Synchronize its query and all commands that update it. Omit query. In multi-threaded programming queries are used infrequently as their values can change asynchronously.

4 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 4 Double-check pattern If callers of unsynchronized queries realize they have just read an illegal value, sometimes they can take a corrective action. –Reaccess the field under synchronization –Get its most current value –Take appropriate action. This is the essence of double check pattern. Useful for lazy initialization Should be used to create singletons in multi- threaded environments.

5 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 5 Singleton pattern for multi-threaded apps public class Singleton { public static Singleton instance(){ //first check if (instance == null) { synchronized(singletonLock){ //double check: second one if (instance == null){ instance = new Singleton; } return instance; } // other methods private Singleton instance; private final singletonLock = new Object(); }

6 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 6 When to use the double-check pattern App has one or more critical sections of code that must execute sequentially. Multiple threads can potentially attempt to execute critical section simultaneously. Critical section is execute just once. Synchronizing the query on every access to critical section causes excessive overhead. This pattern can be used to access the value of a field as well, reducing the use of synchronization.

7 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 7 When not use use double-check pattern Unwise to use it for fields containing references to objects or arrays. Visibility of a reference read without synchronization does not guarantee visibility of non-volatile fields accessed from the reference.Even if a reference is non-null, fields access through it may have stale values. It is difficult at best to use single flag field as an indicator that a whole set of fields must be initialized. The sequential reorderings may cause flag to be visible before other fields are visibly initialized.

8 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 8 Stateless and synchronization Methods in fully immutable objects are stateless, so no sync is needed But statelessness may occur in other kinds of classes. Do not need to synchronize stateless part of methods, allowing for synchronized methods to execute in these sections of code. However can split synchronization only when different parts of the method are not in any way dependent, so that is acceptable for other methods to see and use the object before the full method completion. Data structures that are linked are also amenable to this kinds of manipulations.

9 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 9 Example class ServerWithStateUpdate { private double state; private final Helper helper = new Helper(); public synchronized void service() { state = 2.0f; //...; // set to some new value helper.operation(); } public synchronized double getState() { return state; } }

10 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 10 Example class ServerWithOpenCall { private double state; private final Helper helper = new Helper(); private synchronized void updateState() { state = 2.0f; //...; // set to some new value } public void service() { updateState(); // it grabs the lock helper.operation(); // releases lock } public synchronized double getState() { return state; } }

11 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 11 Splitting synchronization Situation: class can be partitioned into subsets which are: –Independent –Non-interactive –Non-conflicting Useful design technique in OO but much more beneficial in multi-threaded prog. General rule: –The more finely you can subdivide internal synchronization in a class, better liveness properties.

12 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 12 Splitting synchronization Refactoring: –Partition some functionality of a Host class into a Helper –In Host class, declare Helper instance final. –In Host class, forward appropriate methods to Helper as open calls; this works because the methods being called are stateless w.r.t. Host HelperHost Nonsynch method synch method

13 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 13 class Shape { // Incomplete protected double x = 0.0; protected double y = 0.0; protected double width = 0.0; protected double height = 0.0; public synchronized double x() { return x;} public synchronized double y() { return y; } public synchronized double width() { return width;} public synchronized double height() { return height; } public synchronized void adjustLocation() { x = 1; // longCalculation1(); y = 2; //longCalculation2(); } public synchronized void adjustDimensions() { width = 3; // longCalculation3(); height = 4; // longCalculation4(); } //... }

14 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 14 class PassThroughShape { protected final AdjustableLoc loc = new AdjustableLoc(0, 0); protected final AdjustableDim dim = new AdjustableDim(0, 0); public double x() { return loc.x(); } public double y() { return loc.y(); } public double width() { return dim.width(); } public double height() { return dim.height(); } public void adjustLocation() { loc.adjust(); } public void adjustDimensions() { dim.adjust(); } }

15 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 15 class AdjustableLoc { protected double x; protected double y; public AdjustableLoc(double initX, double initY) { x = initX; y = initY; } public synchronized double x() { return x;} public synchronized double y() { return y; } public synchronized void adjust() { x = longCalculation1(); y = longCalculation2(); } protected double longCalculation1() { return 1; /*... */ } protected double longCalculation2() { return 2; /*... */ } }

16 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 16 class AdjustableDim { protected double width; protected double height; public AdjustableDim(double initW, double initH) { width = initW; height = initH; } public synchronized double width() { return width;} public synchronized double height() { return height; } public synchronized void adjust() { width = longCalculation3(); height = longCalculation4(); } protected double longCalculation3() { return 3; /*... */ } protected double longCalculation4() { return 4; /*... */ } }

17 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 17 Splitting locks Idiom: Do not use the “this” lock on an object, use a synchronized block where the lock comes from an instance of Object. Refactoring: –For each independent subset of functionality, declare a final object, lock, initialized in the constructor for the Host and never reinitialized. –Lock object can be of Object or any subclass. –If a subset is uniquely associated with some existing object uniquely referenced from a field, you may use that object as the lock. –One of these locks can be “this” itself. –Declare all methods corresponding to each subset as unsynchronized, but use synchronized blocks in code.

18 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 18 class LockSplitShape { // Incomplete protected double x = 0.0; protected double y = 0.0; protected double width = 0.0; protected double height = 0.0; protected final Object locationLock = new Object(); protected final Object dimensionLock = new Object(); public double x() { synchronized(locationLock) { return x; } public double y() { synchronized(locationLock) { return y; } public void adjustLocation() { synchronized(locationLock) { x = 1; // longCalculation1(); y = 2; // longCalculation2(); } … // etc }

19 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 19 Isolated fields Sometimes classes manage a set of isolated fields, that can be manipulated independent of one another. Use a simple form of splitting to offload synchronization protection to objects used solely to protect basic operations on basic types. These new created classes promise atomicity instead of immutability as in Integer, Float, etc.

20 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 20 class SynchronizedInt { private int value; public SynchronizedInt(int v) { value = v; } public synchronized int get() { return value; } public synchronized int set(int v) { // returns previous value int oldValue = value; value = v; return oldValue; } public synchronized int increment() { return ++value; } // and so on }

21 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 21 class Person { // Fragments //... protected final SynchronizedInt age = new SynchronizedInt(0); protected final SynchronizedBoolean isMarried = new SynchronizedBoolean(false); protected final SynchronizedDouble income = new SynchronizedDouble(0.0); public int getAge() { return age.get(); } public void birthday() { age.increment(); } //... }

22 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 22 Linked data structures Lock splitting can minimize access contention to objects serving as entry points to a linked data structure. In the case of linked structures you can carefully do more refinement in the synchronization.

23 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 23 class LinkedQueue { protected Node head = new Node(null); protected Node last = head; protected final Object pollLock = new Object(); protected final Object getLock = new Object(); public void put(Object x) { Node node = new Node(x); synchronized (putLock) { // insert at end of list synchronized (last) { last.next = node; // extend list last = node; }

24 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 24 Read-only adapters Classes with components should not expose in general their components; but there are cases where clients need to access components for inspection What is commonly done: –Send copies of the components –Use the clone method of component if it has one. All the above may be expensive or impossible.

25 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 25 Read-only adapters In many cases you can selectively permit some leakage by constructing and returning an adapter object surrounding the part that exposes only the operations that clients may use without any interference – usually giving access only to queries.

26 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 26 public Object get() { // returns null if empty synchronized (getLock) { synchronized (head) { Object x = null; Node first = head.next; // get to first real node if (first != null) { x = first.object; first.object = null; // forget old object head = first; // first becomes new head } return x; } static class Node { // local node class for queue Object object; Node next = null; Node(Object x) { object = x; } } } // end of LinkedQueue

27 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 27 Read-only adapters Refactoring: –Define a base interface describing some non- mutative functionality. –Optionally, define a subinterface that supports additional commands used in the Host class. –Define a read-only adapter that forwards only the exported operations. This adapter is final.

28 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 28 class InsufficientFunds extends Exception {} interface Account { long balance(); } interface UpdatableAccount extends Account { void credit(long amount) throws InsufficientFunds; void debit(long amount) throws InsufficientFunds; } // Sample implementation of updatable version class UpdatableAccountImpl implements UpdatableAccount { private long currentBalance; public UpdatableAccountImpl(long initialBalance) { currentBalance = initialBalance; } public synchronized long balance() { return currentBalance; }

29 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 29 public synchronized void credit(long amount) throws InsufficientFunds { if (amount >= 0 || currentBalance >= -amount) currentBalance += amount; else throw new InsufficientFunds(); } public synchronized void debit(long amount) throws InsufficientFunds { credit(-amount); } final class ImmutableAccount implements Account { private Account delegate; public ImmutableAccount(long initialBalance) { delegate = new UpdatableAccountImpl(initialBalance); } ImmutableAccount(Account acct) { delegate = acct; } public long balance() { // forward the immutable method return delegate.balance(); }

30 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 30 class AccountRecorder { // A logging facility public void recordBalance(Account a) { System.out.println(a.balance()); // or record in file } class AccountHolder { private UpdatableAccount acct = new UpdatableAccountImpl(0); private AccountRecorder recorder; public AccountHolder(AccountRecorder r) { recorder = r; } public synchronized void acceptMoney(long amount) { try { acct.credit(amount); recorder.recordBalance(new ImmutableAccount(acct));//(*) } catch (InsufficientFunds ex) { System.out.println("Cannot accept negative amount."); }

31 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 31 class EvilAccountRecorder extends AccountRecorder { private long embezzlement; //... public void recordBalance(Account a) { super.recordBalance(a); if (a instanceof UpdatableAccount) { UpdatableAccount u = (UpdatableAccount)a; try { u.debit(10); embezzlement += 10; } catch (InsufficientFunds quietlyignore) {} } Use of a read-only wrapper in last example seems unnecessary; but it guards against what might happen if someone were to write the following subclass, and use it in conjunction with AccountHolder:

32 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 32 Copy-on-write When a set of fields comprising the state of the object must maintain a set of inter- related invariants, you can isolate these fields in another object that preserves the intended semantics. Rely on immutable representation objects.

33 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 33 class ImmutablePoint { private final int x; private final int y; public ImmutablePoint(int initX, int initY) { x = initX; y = initY; } public int x() { return x; } public int y() { return y; } }

34 Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 34 class Dot { protected ImmutablePoint loc; public Dot(int x, int y) { loc = new ImmutablePoint(x, y); } public synchronized ImmutablePoint location() { return loc; } protected synchronized void updateLoc(ImmutablePoint newLoc) { loc = newLoc; } public void moveTo(int x, int y) { updateLoc(new ImmutablePoint(x, y)); } public synchronized void shiftX(int delta) { updateLoc(new ImmutablePoint(loc.x() + delta, loc.y())); }


Download ppt "Spring/2002 Distributed Software Engineering C:\unocourses\4350\slides\DefiningThreads 1 Reducing synchronization."

Similar presentations


Ads by Google