/* * CSE 332 * SECTION Week 10 */ class Bag { private String s; Bag() { } synchronized void put(String t) { this.s = t; } synchronized String get() { return s; } void changeContents() { this.s = "whatever"; } } // One bad interleaving might be: // Assume all threads can access b1 and b2: Bag b1 = new Bag(); Bag b2 = new Bag(); b2.put("rocks"); // then Thread 1 does: b1.put("gold"); // but here, Thread 2 does: b1.put("rocks"); if(b2.get().equals("rocks")) { b2.put(b1.get()); } // The result will be that b1 gets changed to "rocks" but Thread 1 doesn't // know it, and will store "rocks" into b2 when it meant to put gold there. // let's try solve it by synchronizing on b1: // Assume all threads can access b1 and b2: Bag b1 = new Bag(); Bag b2 = new Bag(); b2.put("rocks"); // then Thread 1 does: synchronized(b1) { b1.put("gold"); // but here, Thread 2 does: b1.put("rocks"); // however, since put is synchronized on "this" and "this" here is b1, // it blocks until Thread 1 releases, so all is good if(b2.get().equals("rocks")) { // but let's say instead, maybe Thread 2 does this here: b2.put("tons of stuff better than gold"); b2.put(b1.get()); } } // now what will happen is, since we didn't synchronize on b2, b2 can be altered in the middle of execution, and we // overwrote stuff that's better than gold with just gold. // So let's try synchronizing on both! Bag b1 = new Bag(); Bag b2 = new Bag(); b2.put("rocks"); // thread 1 synchronized(b1) { synchronized(b2) { b1.put("gold"); // thread 2: b1.put("rocks"); will wait until thread 1 is done with b1 if(b2.get().equals("rocks")) { // thread 2: b2.put("tons of stuff better than gold") will wait until thread 2 is done with b2 b2.put(b1.get()); } } } // but we have another problem... // thread 1 synchronized(b1) { synchronized(b2) { b1.put("gold"); if(b2.get().equals("rocks")) { // thread 2 can do this here: b1.changeContents(); // this will NOT wait, because changeContents was not synchronized // on b1 (or on anything, really) so even though b1 is the lock // when entering changeContents's method in Thread 2, changeContents doesn't // go and check or try to acquire any locks. So it will proceed along merrily.... b2.put(b1.get()); } } } // And at the end of this, both b1 and b2's strings are "whatever" // so to solve this problem, synchronize changeContents inside the Bag class, e.g. synchronized void changeContents() { this.s = "whatever"; }