samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java
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--
Updating to NBMs from NetBeans 8.0.1 as some of them are required to run on JDK8
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
}