Advertisement
dig090

Strange JRC Race Condition

Jun 13th, 2012
1,009
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 3.07 KB | None | 0 0
  1. package com.mprew.be.service.x;
  2.  
  3. import static org.junit.Assert.assertEquals;
  4.  
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Timer;
  10. import java.util.TimerTask;
  11.  
  12. import org.junit.Test;
  13.  
  14. /**
  15.  * This is an interesting test case that seems to be indicating a JRE issue.
  16.  *
  17.  * This comes from http://stackoverflow.com/q/10982941/179850 and the poster named "Luke".
  18.  *
  19.  * I've boiled the code down to its lowest level and added some comments around the changes that can change the error
  20.  * count. This is pretty repeatable to me with 4/5 runs generating errors. If you can't get it to fail I'd try
  21.  * decreasing the fixed-rate period and increasing the NUMBER_TO_USE constant.
  22.  */
  23. public class StrangeRaceConditionTest {
  24.  
  25.     // if this is decreased it may remove the errors
  26.     public static final int NUMBER_TO_USE = 1000000;
  27.  
  28.     private Map<Integer, Buffer> bufferMap = new HashMap<Integer, Buffer>();
  29.  
  30.     public static void main(String[] args) {
  31.         new StrangeRaceConditionTest().strangeRaceConditionTest();
  32.     }
  33.  
  34.     @Test
  35.     public void strangeRaceConditionTest() {
  36.         final Buffer buffer = getBuffer();
  37.  
  38.         TimerTask getBufferTask = new TimerTask() {
  39.             @Override
  40.             public void run() {
  41.                 buffer.getBuffer();
  42.             }
  43.         };
  44.         // if the period is increased it seems to reduce the errors
  45.         new Timer(true).scheduleAtFixedRate(getBufferTask, 0 /* delay ms */, 10 /* period ms */);
  46.  
  47.         for (long i = 0; i < NUMBER_TO_USE; i++) {
  48.             // if we inline the remove() method here then no errors
  49.             // if we change this to buffer.remove() then no errors
  50.             remove();
  51.         }
  52.  
  53.         assertEquals(0, buffer.getErrorC());
  54.     }
  55.  
  56.     private synchronized void remove() {
  57.         Buffer buffer = getBuffer();
  58.         buffer.remove();
  59.     }
  60.  
  61.     private synchronized Buffer getBuffer() {
  62.         // if we remove this whole map nonesense then no errors
  63.         Buffer buffer = bufferMap.get(1);
  64.         // if this test/else is flipped so it is buffer == null ... then no errors
  65.         if (buffer != null) {
  66.             // if this line is commented out then no errors
  67.             buffer = bufferMap.get(1);
  68.         } else {
  69.             buffer = new Buffer();
  70.             bufferMap.put(1, buffer);
  71.         }
  72.         return buffer;
  73.     }
  74.  
  75.     // moving this out to its own class file doesn't seem to help
  76.     private static class Buffer {
  77.         private List<Integer> list = new ArrayList<Integer>();
  78.         private boolean insideGetBuffer = false;
  79.         private int errorC = 0;
  80.  
  81.         public Buffer() {
  82.             // initialize the list
  83.             for (long i = 0; i < NUMBER_TO_USE; i++) {
  84.                 list.add(null);
  85.             }
  86.         }
  87.  
  88.         public synchronized void remove() {
  89.             if (insideGetBuffer) {
  90.                 // adding a System.out.println here makes the problem more repeatable
  91.                 // System.out.println("How did we get here?");
  92.                 errorC++;
  93.             }
  94.         }
  95.  
  96.         public synchronized void getBuffer() {
  97.             insideGetBuffer = true;
  98.             try {
  99.                 // if you comment out this sleep then no errors
  100.                 Thread.sleep(5);
  101.             } catch (Exception e) {
  102.                 e.printStackTrace();
  103.             } finally {
  104.                 insideGetBuffer = false;
  105.             }
  106.         }
  107.  
  108.         public synchronized int getErrorC() {
  109.             return errorC;
  110.         }
  111.     }
  112. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement