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