samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java
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--
Marking code snippets for the "Java Monitor" wiki page
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
}