author | Jaroslav Tulach <jtulach@netbeans.org> |
Wed, 11 Feb 2009 08:52:00 +0100 | |
changeset 317 | e101649dbd17 |
parent 315 | 08dd52950883 |
child 319 | 6c1d8b5553d8 |
permissions | -rw-r--r-- |
jtulach@315 | 1 |
package org.apidesign.javamonitorflaws; |
jtulach@315 | 2 |
|
jtulach@315 | 3 |
import java.beans.PropertyChangeEvent; |
jtulach@315 | 4 |
import java.beans.PropertyChangeListener; |
jtulach@315 | 5 |
import org.netbeans.junit.NbTestCase; |
jtulach@315 | 6 |
|
jtulach@315 | 7 |
public class CacheTest extends NbTestCase { |
jtulach@315 | 8 |
private MultiplyCache cache = new MultiplyCache(); |
jtulach@315 | 9 |
|
jtulach@315 | 10 |
public CacheTest(String n) { |
jtulach@315 | 11 |
super(n); |
jtulach@315 | 12 |
} |
jtulach@315 | 13 |
|
jtulach@315 | 14 |
@Override |
jtulach@315 | 15 |
protected int timeOut() { |
jtulach@315 | 16 |
return 2000; |
jtulach@315 | 17 |
} |
jtulach@315 | 18 |
|
jtulach@315 | 19 |
/** |
jtulach@315 | 20 |
* To simulate deadlock between the cache's setMultiply method and |
jtulach@315 | 21 |
* ToDeadlock's own lock. The root cause is that setMultiply is calling |
jtulach@315 | 22 |
* foreign code while holding the caches's <code>this</code> lock: |
jtulach@315 | 23 |
|
jtulach@315 | 24 |
Thread Test Watch Dog: testDeadlockWithSetter |
jtulach@315 | 25 |
org.apidesign.javamonitorflaws.MultiplyCache.setMultiply:19 |
jtulach@315 | 26 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.assertMultiplyByTen:40 |
jtulach@315 | 27 |
org.apidesign.javamonitorflaws.CacheTest.testDeadlockWithSetter:50 |
jtulach@315 | 28 |
sun.reflect.NativeMethodAccessorImpl.invoke0:-2 |
jtulach@315 | 29 |
sun.reflect.NativeMethodAccessorImpl.invoke:39 |
jtulach@315 | 30 |
sun.reflect.DelegatingMethodAccessorImpl.invoke:25 |
jtulach@315 | 31 |
java.lang.reflect.Method.invoke:597 |
jtulach@315 | 32 |
junit.framework.TestCase.runTest:168 |
jtulach@315 | 33 |
org.netbeans.junit.NbTestCase.access$200:84 |
jtulach@315 | 34 |
org.netbeans.junit.NbTestCase$2.doSomething:328 |
jtulach@315 | 35 |
org.netbeans.junit.NbTestCase$1Guard.run:265 |
jtulach@315 | 36 |
java.lang.Thread.run:619 |
jtulach@315 | 37 |
Thread to deadlock |
jtulach@315 | 38 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.assertMultiplyByTen:40 |
jtulach@315 | 39 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.propertyChange:36 |
jtulach@315 | 40 |
java.beans.PropertyChangeSupport.firePropertyChange:339 |
jtulach@315 | 41 |
java.beans.PropertyChangeSupport.firePropertyChange:276 |
jtulach@315 | 42 |
java.beans.PropertyChangeSupport.firePropertyChange:297 |
jtulach@315 | 43 |
org.apidesign.javamonitorflaws.MultiplyCache.setMultiply:21 |
jtulach@315 | 44 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.run:28 |
jtulach@315 | 45 |
java.lang.Thread.run:619 |
jtulach@315 | 46 |
|
jtulach@315 | 47 |
*/ |
jtulach@315 | 48 |
public void testDeadlockWithSetter() throws Exception { |
jtulach@315 | 49 |
if (Boolean.getBoolean("no.failures")) return; |
jtulach@315 | 50 |
|
jtulach@315 | 51 |
class ToDeadlock implements Runnable, PropertyChangeListener { |
jtulach@315 | 52 |
int value; |
jtulach@315 | 53 |
|
jtulach@315 | 54 |
public void run() { |
jtulach@315 | 55 |
cache.setMultiply(10); |
jtulach@315 | 56 |
} |
jtulach@315 | 57 |
public void propertyChange(PropertyChangeEvent evt) { |
jtulach@315 | 58 |
try { |
jtulach@315 | 59 |
Thread.sleep(500); |
jtulach@315 | 60 |
} catch (InterruptedException ex) { |
jtulach@315 | 61 |
// ok |
jtulach@315 | 62 |
} |
jtulach@315 | 63 |
changeMultiplyToSeven(); |
jtulach@315 | 64 |
} |
jtulach@315 | 65 |
|
jtulach@315 | 66 |
public synchronized void changeMultiplyToSeven() { |
jtulach@315 | 67 |
cache.setMultiply(7); |
jtulach@315 | 68 |
} |
jtulach@315 | 69 |
} |
jtulach@315 | 70 |
ToDeadlock toDeadlock = new ToDeadlock(); |
jtulach@315 | 71 |
cache.addPropertyChangeListener(toDeadlock); |
jtulach@315 | 72 |
Thread t = new Thread(toDeadlock, "to deadlock"); |
jtulach@315 | 73 |
t.start(); |
jtulach@315 | 74 |
|
jtulach@315 | 75 |
Thread.sleep(100); |
jtulach@315 | 76 |
|
jtulach@315 | 77 |
toDeadlock.changeMultiplyToSeven(); |
jtulach@315 | 78 |
} |
jtulach@315 | 79 |
|
jtulach@315 | 80 |
/** Shows that one can deadlock with the cache's API even the API |
jtulach@315 | 81 |
* is locally correctly synchronized. |
jtulach@315 | 82 |
Thread Test Watch Dog: testDeadlockWithTheAPICacheItself |
jtulach@315 | 83 |
org.apidesign.javamonitorflaws.Cache.get:16 |
jtulach@315 | 84 |
org.apidesign.javamonitorflaws.CacheTest$2ToDeadlock.assertMultiplyByTen |
jtulach@315 | 85 |
org.apidesign.javamonitorflaws.CacheTest.testDeadlockViaAPI:112 |
jtulach@315 | 86 |
java.lang.reflect.Method.invoke:597 |
jtulach@315 | 87 |
org.netbeans.junit.NbTestCase.access$200:84 |
jtulach@315 | 88 |
org.netbeans.junit.NbTestCase$2.doSomething:328 |
jtulach@315 | 89 |
org.netbeans.junit.NbTestCase$1Guard.run:265 |
jtulach@315 | 90 |
java.lang.Thread.run:619 |
jtulach@315 | 91 |
Thread Deadlock using API |
jtulach@315 | 92 |
org.apidesign.javamonitorflaws.CacheTest$2ToDeadlock.assertMultiplyByTen |
jtulach@315 | 93 |
org.apidesign.javamonitorflaws.CacheTest$2ToDeadlock.propertyChange:98 |
jtulach@315 | 94 |
java.beans.PropertyChangeSupport.firePropertyChange:339 |
jtulach@315 | 95 |
java.beans.PropertyChangeSupport.firePropertyChange:276 |
jtulach@315 | 96 |
java.beans.PropertyChangeSupport.firePropertyChange:297 |
jtulach@315 | 97 |
org.apidesign.javamonitorflaws.MultiplyCache.setMultiply:21 |
jtulach@315 | 98 |
org.apidesign.javamonitorflaws.CacheTest$2ToDeadlock.run:90 |
jtulach@315 | 99 |
java.lang.Thread.run:619 |
jtulach@315 | 100 |
*/ |
jtulach@317 | 101 |
// BEGIN: monitor.pitfalls.block.propertychange |
jtulach@315 | 102 |
public void testDeadlockViaAPI() throws Exception { |
jtulach@315 | 103 |
if (Boolean.getBoolean("no.failures")) return; |
jtulach@315 | 104 |
|
jtulach@315 | 105 |
class ToDeadlock implements Runnable, PropertyChangeListener { |
jtulach@317 | 106 |
int lastMultiply; |
jtulach@317 | 107 |
|
jtulach@315 | 108 |
public void run() { |
jtulach@315 | 109 |
cache.setMultiply(10); |
jtulach@315 | 110 |
} |
jtulach@315 | 111 |
public void propertyChange(PropertyChangeEvent evt) { |
jtulach@315 | 112 |
try { |
jtulach@317 | 113 |
storeMultiply(); |
jtulach@315 | 114 |
} catch (InterruptedException ex) { |
jtulach@315 | 115 |
// ok |
jtulach@315 | 116 |
} |
jtulach@315 | 117 |
} |
jtulach@315 | 118 |
|
jtulach@317 | 119 |
private synchronized void storeMultiply() |
jtulach@317 | 120 |
throws InterruptedException { |
jtulach@317 | 121 |
lastMultiply = cache.getMultiply(); |
jtulach@317 | 122 |
// simulates "starvation" |
jtulach@317 | 123 |
wait(); |
jtulach@317 | 124 |
} |
jtulach@317 | 125 |
|
jtulach@317 | 126 |
public void assertMultiplyByTen() { |
jtulach@315 | 127 |
} |
jtulach@315 | 128 |
} |
jtulach@315 | 129 |
ToDeadlock toDeadlock = new ToDeadlock(); |
jtulach@315 | 130 |
cache.addPropertyChangeListener(toDeadlock); |
jtulach@315 | 131 |
Thread t = new Thread(toDeadlock, "Deadlock using API"); |
jtulach@315 | 132 |
t.start(); |
jtulach@315 | 133 |
|
jtulach@315 | 134 |
Thread.sleep(100); |
jtulach@315 | 135 |
|
jtulach@317 | 136 |
// BEGIN: monitor.pitfalls.brokencall |
jtulach@317 | 137 |
int value = cache.get("123"); |
jtulach@317 | 138 |
assertEquals("3*10=30", 30, value); |
jtulach@317 | 139 |
// END: monitor.pitfalls.brokencall |
jtulach@315 | 140 |
} |
jtulach@317 | 141 |
// END: monitor.pitfalls.block.propertychange |
jtulach@315 | 142 |
} |