Oh what a tangled web we weave when first to thread we do conceive.
History Last time Threads & synchronization This time: Team tips Synchronization, cont’d. Design exercise
Team tip: code ownership Who “owns” a module? Who is responsible for it? Model 1: Strong individual ownership One person is exclusive owner of each module Knows it inside out Can easily fix bugs, etc. Clear-cut lines of responsibility Each developer has limited responsibility All changes have to pass through one person Can be a serious bottleneck
Team tip: code ownership Loose ownership model Whole code base is “owned” by group Indivs may work primarily on one aspect, but anybody has rights to change anything Fewer bottlenecks More responsive to individual needs Individuals have to be generalists, not specialists Less familiarity ⇒ very easy to introduce bugs Esp. integration bugs Regression testing critical
The truth of synchronized Java synchronized keyword just means: get lock before proceeding; release lock when done
The truth of synchronized public class Panopticon { private double[] _data; public synchronized void set(int idx, double v) { _data[idx]=v; } public synchronized double get(int idx) { return _data[idx]; }
The truth of synchronized public class Panopticon { private double[] _data; hidden Object _lockID_=null; public void set(int idx, double v) { while (!_testAndSet_(_lockID_==null || _lockID==this,this)); _data[idx]=v; _atomicSet_(_lockID,null); } public double get(int idx) { while (!_testAndSet_(_lockID_==null || _lockID_==this,this)); int result=_data[idx]; _atomicSet_(_lockID_,null); return result; }
The truth of synchronized Java synchronized keyword just means: get lock before proceeding; release lock when done synchronized method: only one thread can execute this method at a time (*) synchronized block: only one thread can execute this block at a time (*)
Where is the lock? Caveat: synchronized methods/blocks are only mutex with respect to a single lock Have to make sure that all threads are using the same lock Where does the lock variable live? non-static synchronized methods: lives on the object instance static synchronized methods: lives on the class variable synchronized block: lives on the object named in the argument
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; }
Who owns the lock? The memory picture:
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } } Answer: “ this ” owns it (object on which getX0() is being called)
Who owns the lock? The memory picture:
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} } Answer: x itself owns the lock
Who owns the lock? The memory picture:
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} public List getX2() { synchronized(this) { return x; } } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} public List getX2() { synchronized(this) { return x; } } } Again, “ this ” owns it (duh)
Who owns the lock? The memory picture:
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} public List getX2() { synchronized(this) { return x; } } public synchronized List getX3() { synchronized(x) { return x; } } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getX0() { return x; } public List getX1() { synchronized(x){return x; }} public List getX2() { synchronized(this) { return x; } } public synchronized List getX3() { synchronized(x) { return x; } } } Trick question! Both locks ( this and x ) have to be acquired!
Who owns the lock? The memory picture:
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getA0() { return a; } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getA0() { return a; } } Same old, same old. “ this ” has the lock.
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getA0() { return a; } public int getA1() { synchronized(a){ return a; }} }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getA0() { return a; } public int getA1() { synchronized(a){ return a; }} } Another trick question! a is atomic -- it’s not an Object, and doesn’t have hidden state.
Who owns the lock? The memory picture: ???
Who owns the lock? Error you get from trying to synchronize on an atomic field: WhoOwnsTheLock.java:12: incompatible types found : int required: java.lang.Object public int getA1() { synchronized(a) { return a; } } ^ 1 error
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } } Again, “ this ” owns the lock.
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } } Again, “ this ” owns the lock. Danger Will Robinson! Can have multiple access to y !!!
Who owns the lock? Consider: WhoOwnsTheLock foo=new WhoOwnsTheLock(); WhoOwnsTheLock bar=new WhoOwnsTheLock();
Who owns the lock?
Consider: WhoOwnsTheLock foo=new WhoOwnsTheLock(); WhoOwnsTheLock bar=new WhoOwnsTheLock(); // in thread 0 foo.getY0(); // in thread 1 bar.getY0();
Who owns the lock? thread 0 synch w/ this lock
Who owns the lock? thread 0 synch w/ this lock & thread 1 synch w/ this one
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } public static synchronized List getY1() { return y; }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } public static synchronized List getY1() { return y; } Remember: “ static ”==“associated with class” (i.e., class object). So this is synchronized on the class object. No more conflict. (yay!)
Who owns the lock?
public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } public static synchronized List getY1() { return y; } public static List getY2() { synchronized(y) { return y; } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized List getY0() { return y; } public static synchronized List getY1() { return y; } public static List getY2() { synchronized(y) { return y; } } Effectively, just as good as previous version...
Who owns the lock?
public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getXY0() { return x.size()+y.size(); }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getXY0() { return x.size()+y.size(); } Synchronized on “ this ”, but can have concurrent access via y ( x is safe)
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getXY0() { return x.size()+y.size(); } public static synchronized int getXY1() { return x.size()+y.size(); }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getXY0() { return x.size()+y.size(); } public static synchronized int getXY1() { return x.size()+y.size(); } Same problem, but in reverse -- y is safe, but can have multi-access to x.
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public synchronized int getXY0() { return x.size()+y.size(); } public static synchronized int getXY1() { return x.size()+y.size(); } public int getXY2() { synchronized(this) { // or on x itself synchronized(y) { return x.size()+y.size(); } } } }
Who owns the lock?
public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public int getAB0() { synchronized(this) { synhronized(b) { // oh oh... b is atomic return a+b; } } } }
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public int getAB0() { synchronized(this) { synhronized(y) { return a+b; } } } } Answer 1: synchronize on something “near” b (i.e., something else static) that isn’t, itself, atomic. Sometimes introduce spurious “ Object ” just for this
Who owns the lock? public class WhoOwnsTheLock { private List x=new LinkedList(); private static List y=new LinkedList(); private int a=3; private static int b=42; public static synchronized int getAB1() { synchronized(this) { return a+b; } } } Answer 2: synchronize on class object (via “ static synchronized ” method declaration)