author | Jaroslav Tulach <jaroslav.tulach@apidesign.org> |
Thu, 30 Oct 2014 21:30:10 +0100 | |
changeset 409 | 40cabcdcd2be |
parent 317 | e101649dbd17 |
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 |
public CacheTest(String n) { |
jtulach@315 | 9 |
super(n); |
jtulach@315 | 10 |
} |
jtulach@315 | 11 |
|
jtulach@315 | 12 |
@Override |
jtulach@315 | 13 |
protected int timeOut() { |
jtulach@315 | 14 |
return 2000; |
jtulach@315 | 15 |
} |
jtulach@315 | 16 |
|
jtulach@315 | 17 |
/** |
jtulach@315 | 18 |
* To simulate deadlock between the cache's setMultiply method and |
jtulach@315 | 19 |
* ToDeadlock's own lock. The root cause is that setMultiply is calling |
jtulach@315 | 20 |
* foreign code while holding the caches's <code>this</code> lock: |
jtulach@315 | 21 |
|
jtulach@315 | 22 |
Thread Test Watch Dog: testDeadlockWithSetter |
jtulach@315 | 23 |
org.apidesign.javamonitorflaws.MultiplyCache.setMultiply:19 |
jtulach@315 | 24 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.assertMultiplyByTen:40 |
jtulach@315 | 25 |
org.apidesign.javamonitorflaws.CacheTest.testDeadlockWithSetter:50 |
jtulach@315 | 26 |
sun.reflect.NativeMethodAccessorImpl.invoke0:-2 |
jtulach@315 | 27 |
sun.reflect.NativeMethodAccessorImpl.invoke:39 |
jtulach@315 | 28 |
sun.reflect.DelegatingMethodAccessorImpl.invoke:25 |
jtulach@315 | 29 |
java.lang.reflect.Method.invoke:597 |
jtulach@315 | 30 |
junit.framework.TestCase.runTest:168 |
jtulach@315 | 31 |
org.netbeans.junit.NbTestCase.access$200:84 |
jtulach@315 | 32 |
org.netbeans.junit.NbTestCase$2.doSomething:328 |
jtulach@315 | 33 |
org.netbeans.junit.NbTestCase$1Guard.run:265 |
jtulach@315 | 34 |
java.lang.Thread.run:619 |
jtulach@315 | 35 |
Thread to deadlock |
jtulach@315 | 36 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.assertMultiplyByTen:40 |
jtulach@315 | 37 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.propertyChange:36 |
jtulach@315 | 38 |
java.beans.PropertyChangeSupport.firePropertyChange:339 |
jtulach@315 | 39 |
java.beans.PropertyChangeSupport.firePropertyChange:276 |
jtulach@315 | 40 |
java.beans.PropertyChangeSupport.firePropertyChange:297 |
jtulach@315 | 41 |
org.apidesign.javamonitorflaws.MultiplyCache.setMultiply:21 |
jtulach@315 | 42 |
org.apidesign.javamonitorflaws.CacheTest$1ToDeadlock.run:28 |
jtulach@315 | 43 |
java.lang.Thread.run:619 |
jtulach@315 | 44 |
|
jtulach@315 | 45 |
*/ |
jtulach@315 | 46 |
public void testDeadlockWithSetter() throws Exception { |
jtulach@315 | 47 |
if (Boolean.getBoolean("no.failures")) return; |
jtulach@315 | 48 |
|
jtulach@319 | 49 |
final CacheToTest cache = new MultiplyCache(); |
jtulach@319 | 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@315 | 101 |
public void testDeadlockViaAPI() throws Exception { |
jtulach@315 | 102 |
if (Boolean.getBoolean("no.failures")) return; |
jtulach@319 | 103 |
testDeadlockViaAPI(new MultiplyCache()); |
jtulach@319 | 104 |
} |
jtulach@319 | 105 |
|
jtulach@319 | 106 |
// BEGIN: monitor.pitfalls.block.propertychange |
jtulach@319 | 107 |
private static void testDeadlockViaAPI(final CacheToTest cache) |
jtulach@319 | 108 |
throws Exception { |
jtulach@315 | 109 |
class ToDeadlock implements Runnable, PropertyChangeListener { |
jtulach@317 | 110 |
int lastMultiply; |
jtulach@317 | 111 |
|
jtulach@315 | 112 |
public void run() { |
jtulach@315 | 113 |
cache.setMultiply(10); |
jtulach@315 | 114 |
} |
jtulach@315 | 115 |
public void propertyChange(PropertyChangeEvent evt) { |
jtulach@315 | 116 |
try { |
jtulach@317 | 117 |
storeMultiply(); |
jtulach@315 | 118 |
} catch (InterruptedException ex) { |
jtulach@315 | 119 |
// ok |
jtulach@315 | 120 |
} |
jtulach@315 | 121 |
} |
jtulach@315 | 122 |
|
jtulach@317 | 123 |
private synchronized void storeMultiply() |
jtulach@317 | 124 |
throws InterruptedException { |
jtulach@317 | 125 |
lastMultiply = cache.getMultiply(); |
jtulach@317 | 126 |
// simulates "starvation" |
jtulach@317 | 127 |
wait(); |
jtulach@317 | 128 |
} |
jtulach@317 | 129 |
|
jtulach@317 | 130 |
public void assertMultiplyByTen() { |
jtulach@315 | 131 |
} |
jtulach@315 | 132 |
} |
jtulach@315 | 133 |
ToDeadlock toDeadlock = new ToDeadlock(); |
jtulach@315 | 134 |
cache.addPropertyChangeListener(toDeadlock); |
jtulach@315 | 135 |
Thread t = new Thread(toDeadlock, "Deadlock using API"); |
jtulach@315 | 136 |
t.start(); |
jtulach@315 | 137 |
|
jtulach@315 | 138 |
Thread.sleep(100); |
jtulach@315 | 139 |
|
jtulach@317 | 140 |
// BEGIN: monitor.pitfalls.brokencall |
jtulach@317 | 141 |
int value = cache.get("123"); |
jtulach@317 | 142 |
assertEquals("3*10=30", 30, value); |
jtulach@317 | 143 |
// END: monitor.pitfalls.brokencall |
jtulach@315 | 144 |
} |
jtulach@317 | 145 |
// END: monitor.pitfalls.block.propertychange |
jtulach@319 | 146 |
|
jtulach@319 | 147 |
public void testDeadlockViaAPIWithCacheOK() throws Exception { |
jtulach@319 | 148 |
testDeadlockViaAPI(new MultiplyCacheOK()); |
jtulach@319 | 149 |
} |
jtulach@319 | 150 |
|
jtulach@319 | 151 |
static interface CacheToTest { |
jtulach@319 | 152 |
public Integer get(String key); |
jtulach@319 | 153 |
|
jtulach@319 | 154 |
public void setMultiply(int m); |
jtulach@319 | 155 |
public int getMultiply(); |
jtulach@319 | 156 |
public void addPropertyChangeListener(PropertyChangeListener l); |
jtulach@319 | 157 |
public void removePropertyChangeListener(PropertyChangeListener l); |
jtulach@319 | 158 |
} |
jtulach@315 | 159 |
} |