samples/deadlock/test/org/apidesign/javamonitorflaws/CacheTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 10 Feb 2009 18:36:21 +0100
changeset 315 08dd52950883
child 317 e101649dbd17
permissions -rw-r--r--
Example for the "java monitor pitfalls" chapter
     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     public void testDeadlockViaAPI() throws Exception {
   102         if (Boolean.getBoolean("no.failures")) return;
   103         
   104         class ToDeadlock implements Runnable, PropertyChangeListener {
   105             public void run() {
   106                 cache.setMultiply(10);
   107             }
   108             public void propertyChange(PropertyChangeEvent evt) {
   109                 try {
   110                     Thread.sleep(500);
   111                 } catch (InterruptedException ex) {
   112                     // ok
   113                 }
   114                 assertMultiplyByTen();
   115             }
   116 
   117             public synchronized void assertMultiplyByTen() {
   118                 int value =  cache.get("123");
   119                 assertEquals("3*10=30", 30, value);
   120             }
   121         }
   122         ToDeadlock toDeadlock = new ToDeadlock();
   123         cache.addPropertyChangeListener(toDeadlock);
   124         Thread t = new Thread(toDeadlock, "Deadlock using API");
   125         t.start();
   126 
   127         Thread.sleep(100);
   128 
   129         toDeadlock.assertMultiplyByTen();
   130     }
   131 }